Thanks for the review. On 2017/03/06 15:41, Michael Paquier wrote: > On Fri, Mar 3, 2017 at 10:02 AM, Amit Langote > <langote_amit...@lab.ntt.co.jp> wrote: >> Thanks. I noticed that 'and' is duplicated in a line added by the commit >> to analyze.sgml. Attached 0001 fixes that. 0002 and 0003 same as the >> last version. > > /* > - * If all the children were temp tables, pretend it's a non-inheritance > - * situation. The duplicate RTE we added for the parent table is > - * harmless, so we don't bother to get rid of it; ditto for the useless > - * PlanRowMark node. > + * If all the children were temp tables or if the parent is a partitioned > + * table without any leaf partitions, pretend it's a non-inheritance > + * situation. The duplicate RTE for the parent table we added in the > + * non-partitioned table case is harmless, so we don't bother to get rid > + * of it; ditto for the useless PlanRowMark node. > */ > - if (list_length(appinfos) < 2) > + if (!has_child) > This comment is not completely correct. Children can be temp tables, > they just cannot be temp tables of other backends. It seems to me that > you could still keep this code simple and remove has_child..
I updated the comment. I recall having posted a patch for that once, but perhaps went unnoticed. About has_child, the other option is to make the minimum length of appinfos list relkind-based, but the condition quickly becomes ugly. Do you have a suggestion? > @@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, > case RELKIND_RELATION: > case RELKIND_TOASTVALUE: > case RELKIND_MATVIEW: > - case RELKIND_PARTITIONED_TABLE: > options = heap_reloptions(classForm->relkind, datum, false); > break; > Partitioned tables cannot have reloptions? What about all the > autovacuum_* parameters then? Those are mainly not storage-related. AFAIK, none of the heap reloptions will be applicable to partitioned table relations once we eliminate storage. About autovacuum_* parameters - we currently don't handle partitioned tables in autovacuum.c, because no statistics are reported for them. That is, relation_needs_vacanalyze() will never return true for dovacuum, doanalyze and wraparound if it is passed a RELKIND_PARTITIONED_TABLE relation. That's something to be fixed separately though. When we add autovacuum support for partitioned tables, we may want to add a new set of reloptions (new because partitioned tables still won't support all options returned by heap_reloptions()). Am I missing something? Thanks, Amit
>From 7cea5e205742c14893a8f52f213118b7de091062 Mon Sep 17 00:00:00 2001 From: amit <amitlangot...@gmail.com> Date: Fri, 3 Mar 2017 09:57:11 +0900 Subject: [PATCH 1/3] Fix duplicated 'and' in analyze.sgml --- doc/src/sgml/ref/analyze.sgml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/analyze.sgml b/doc/src/sgml/ref/analyze.sgml index 49727e22df..45dee101df 100644 --- a/doc/src/sgml/ref/analyze.sgml +++ b/doc/src/sgml/ref/analyze.sgml @@ -64,7 +64,7 @@ ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table_name</replaceable> [ <para> The name (possibly schema-qualified) of a specific table to analyze. If omitted, all regular tables, partitioned tables, and - and materialized views in the current database are analyzed (but not + materialized views in the current database are analyzed (but not foreign tables). If the specified table is a partitioned table, both the inheritance statistics of the partitioned table as a whole and statistics of the individual partitions are updated. -- 2.11.0
>From 8ad7b95c56cd261b4581447aed1f3a6519b8ae06 Mon Sep 17 00:00:00 2001 From: amit <amitlangot...@gmail.com> Date: Mon, 6 Feb 2017 17:26:48 +0900 Subject: [PATCH 2/3] Avoid creating scan nodes for partitioned tables * Currently, we create scan nodes for inheritance parents in their role as an inheritance set member. Partitioned tables do not contain any data, so it's useless to create scan nodes for them. So we need not create AppendRelInfo's for them in the planner prep phase. * The planner prep phase turns off inheritance on the parent RTE if there isn't at least one child member (other than the parent itself which in normal cases is also a child member), which means the latter phases will not consider creating an Append plan and instead create a scan node. Avoid this if the RTE is a partitioned table, by noticing such cases in set_rel_size(). Per suggestion from Ashutosh Bapat. * Since we do not add the RTE corresponding to the root partitioned table as the 1st child member of the inheritance set, inheritance_planner() must not assume the same when assigning nominalRelation to a ModifyTable node. * In ExecInitModifyTable(), use nominalRelation to initialize tuple routing information, instead of the first resultRelInfo. We set ModifyTable.nominalRelation to the root parent RTE in the partitioned table case (implicitly in the INSERT case, whereas explicitly in the UPDATE/DELETE cases). --- src/backend/executor/nodeModifyTable.c | 18 +++-- src/backend/optimizer/path/allpaths.c | 8 ++ src/backend/optimizer/plan/planner.c | 14 +++- src/backend/optimizer/prep/prepunion.c | 32 ++++++-- src/test/regress/expected/inherit.out | 124 ++++++++++-------------------- src/test/regress/expected/tablesample.out | 4 +- src/test/regress/sql/inherit.sql | 8 ++ 7 files changed, 108 insertions(+), 100 deletions(-) diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 95e158970c..188ce8f8d4 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -45,6 +45,7 @@ #include "foreign/fdwapi.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" +#include "parser/parsetree.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "utils/builtins.h" @@ -1634,7 +1635,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) Plan *subplan; ListCell *l; int i; - Relation rel; + Relation nominalRel; + RangeTblEntry *nominalRTE; /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); @@ -1726,9 +1728,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) estate->es_result_relation_info = saved_resultRelInfo; /* Build state for INSERT tuple routing */ - rel = mtstate->resultRelInfo->ri_RelationDesc; + nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table); + nominalRel = heap_open(nominalRTE->relid, NoLock); if (operation == CMD_INSERT && - rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + nominalRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { PartitionDispatch *partition_dispatch_info; ResultRelInfo *partitions; @@ -1737,7 +1740,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) int num_parted, num_partitions; - ExecSetupPartitionTupleRouting(rel, + ExecSetupPartitionTupleRouting(nominalRel, &partition_dispatch_info, &partitions, &partition_tupconv_maps, @@ -1801,7 +1804,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* varno = node->nominalRelation */ mapped_wcoList = map_partition_varattnos(wcoList, node->nominalRelation, - partrel, rel); + partrel, nominalRel); foreach(ll, mapped_wcoList) { WithCheckOption *wco = (WithCheckOption *) lfirst(ll); @@ -1876,7 +1879,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* varno = node->nominalRelation */ rlist = map_partition_varattnos(returningList, node->nominalRelation, - partrel, rel); + partrel, nominalRel); rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps); resultRelInfo->ri_projectReturning = ExecBuildProjectionInfo(rliststate, econtext, slot, @@ -1897,6 +1900,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) mtstate->ps.ps_ExprContext = NULL; } + /* We're done using it. */ + heap_close(nominalRel, NoLock); + /* * If needed, Initialize target list, projection and qual for ON CONFLICT * DO UPDATE. diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 633b5c1608..f2c8d27193 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel, /* Foreign table */ set_foreign_size(root, rel, rte); } + else if (rte->relkind == RELKIND_PARTITIONED_TABLE) + { + /* + * A partitioned table without leaf partitions is marked + * as a dummy rel. + */ + set_dummy_rel_pathlist(rel); + } else if (rte->tablesample != NULL) { /* Sampled relation */ diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index ca0ae7883e..b5698f0ce7 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root) RelOptInfo *final_rel; ListCell *lc; Index rti; + RangeTblEntry *parent_rte; Assert(parse->commandType != CMD_INSERT); /* + * If the parent RTE is a partitioned table, we should use that as the + * nominal relation, because we do not have the duplicate parent RTE, + * unlike in the case of a non-partitioned inheritance parent. + */ + parent_rte = rt_fetch(parentRTindex, root->parse->rtable); + if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE) + nominalRelation = parentRTindex; + + /* * We generate a modified instance of the original Query for each target * relation, plan that, and put all the plans into a list that will be * controlled by a single ModifyTable node. All the instances share the @@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root) { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc); PlannerInfo *subroot; - RangeTblEntry *parent_rte; RangeTblEntry *child_rte; RelOptInfo *sub_final_rel; Path *subpath; @@ -1214,6 +1223,9 @@ inheritance_planner(PlannerInfo *root) * will not be otherwise referenced in the plan, doing so would give * rise to confusing use of multiple aliases in EXPLAIN output for * what the user will think is the "same" table.) + * + * If the parent is a partitioned table, we already set the nominal + * relation. */ if (nominalRelation < 0) nominalRelation = appinfo->child_relid; diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 1389db18ba..7bd4928945 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -1364,6 +1364,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) List *inhOIDs; List *appinfos; ListCell *l; + bool has_child; /* Does RT entry allow inheritance? */ if (!rte->inh) @@ -1435,6 +1436,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) /* Scan the inheritance set and expand it */ appinfos = NIL; + has_child = false; foreach(l, inhOIDs) { Oid childOID = lfirst_oid(l); @@ -1450,6 +1452,22 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) newrelation = oldrelation; /* + * Since partitioned tables themselves do not contain data, later + * planning steps should not create scan nodes for them. So do not + * create the child RTE and AppendRelInfo. + */ + if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + /* + * Don't lose the lock taken for us by find_all_inheritors() + * lest its partitions change under us. + */ + if (newrelation != oldrelation) + heap_close(newrelation, NoLock); + continue; + } + + /* * It is possible that the parent table has children that are temp * tables of other backends. We cannot safely access such tables * (because of buffering issues), and the best thing to do seems to be @@ -1461,6 +1479,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) continue; } + /* We have a child table. */ + has_child = true; + /* * Build an RTE for the child, and attach to query's rangetable list. * We copy most fields of the parent's RTE, but replace relation OID @@ -1545,12 +1566,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) heap_close(oldrelation, NoLock); /* - * If all the children were temp tables, pretend it's a non-inheritance - * situation. The duplicate RTE we added for the parent table is - * harmless, so we don't bother to get rid of it; ditto for the useless - * PlanRowMark node. + * If all the children were temp tables of other backends or if the parent + * is a partitioned table without any leaf partitions, pretend it's a + * non-inheritance situation. The duplicate RTE for the parent table we + * added in the non-partitioned table case is harmless, so we don't bother + * to get rid of it; ditto for the useless PlanRowMark node. */ - if (list_length(appinfos) < 2) + if (!has_child) { /* Clear flag before returning */ rte->inh = false; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index a8c8b28a75..55b147432f 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1598,6 +1598,14 @@ reset enable_bitmapscan; create table list_parted ( a varchar ) partition by list (a); +-- test scanning partitioned table without any partitions +explain (costs off) select * from list_parted; + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + create table part_ab_cd partition of list_parted for values in ('ab', 'cd'); create table part_ef_gh partition of list_parted for values in ('ef', 'gh'); create table part_null_xy partition of list_parted for values in (null, 'xy'); @@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted; QUERY PLAN -------------------------------- Append - -> Seq Scan on list_parted -> Seq Scan on part_ab_cd -> Seq Scan on part_ef_gh -> Seq Scan on part_null_xy -(5 rows) +(4 rows) explain (costs off) select * from list_parted where a is null; QUERY PLAN -------------------------------- Append - -> Seq Scan on list_parted - Filter: (a IS NULL) -> Seq Scan on part_null_xy Filter: (a IS NULL) -(5 rows) +(3 rows) explain (costs off) select * from list_parted where a is not null; QUERY PLAN --------------------------------- Append - -> Seq Scan on list_parted - Filter: (a IS NOT NULL) -> Seq Scan on part_ab_cd Filter: (a IS NOT NULL) -> Seq Scan on part_ef_gh Filter: (a IS NOT NULL) -> Seq Scan on part_null_xy Filter: (a IS NOT NULL) -(9 rows) +(7 rows) explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); QUERY PLAN ---------------------------------------------------------- Append - -> Seq Scan on list_parted - Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) -> Seq Scan on part_ab_cd Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) -> Seq Scan on part_ef_gh Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) -(7 rows) +(5 rows) explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd'); QUERY PLAN --------------------------------------------------------------------------------------- Append - -> Seq Scan on list_parted - Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) -> Seq Scan on part_ab_cd Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) -> Seq Scan on part_ef_gh Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) -> Seq Scan on part_null_xy Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) -(9 rows) +(7 rows) explain (costs off) select * from list_parted where a = 'ab'; QUERY PLAN ------------------------------------------ Append - -> Seq Scan on list_parted - Filter: ((a)::text = 'ab'::text) -> Seq Scan on part_ab_cd Filter: ((a)::text = 'ab'::text) -(5 rows) +(3 rows) create table range_list_parted ( a int, b char(2) ) partition by range (a); create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b); +-- test scanning partitioned table without any leaf partitions +explain (costs off) select * from range_list_parted; + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + create table part_1_10_ab partition of part_1_10 for values in ('ab'); create table part_1_10_cd partition of part_1_10 for values in ('cd'); create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b); @@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab'); create table part_40_inf_cd partition of part_40_inf for values in ('cd'); create table part_40_inf_null partition of part_40_inf for values in (null); explain (costs off) select * from range_list_parted; - QUERY PLAN -------------------------------------- + QUERY PLAN +------------------------------------ Append - -> Seq Scan on range_list_parted - -> Seq Scan on part_1_10 - -> Seq Scan on part_10_20 - -> Seq Scan on part_21_30 - -> Seq Scan on part_40_inf -> Seq Scan on part_1_10_ab -> Seq Scan on part_1_10_cd -> Seq Scan on part_10_20_ab @@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted; -> Seq Scan on part_40_inf_ab -> Seq Scan on part_40_inf_cd -> Seq Scan on part_40_inf_null -(15 rows) +(10 rows) explain (costs off) select * from range_list_parted where a = 5; - QUERY PLAN -------------------------------------- + QUERY PLAN +-------------------------------- Append - -> Seq Scan on range_list_parted - Filter: (a = 5) - -> Seq Scan on part_1_10 - Filter: (a = 5) -> Seq Scan on part_1_10_ab Filter: (a = 5) -> Seq Scan on part_1_10_cd Filter: (a = 5) -(9 rows) +(5 rows) explain (costs off) select * from range_list_parted where b = 'ab'; - QUERY PLAN -------------------------------------- + QUERY PLAN +------------------------------------ Append - -> Seq Scan on range_list_parted - Filter: (b = 'ab'::bpchar) - -> Seq Scan on part_1_10 - Filter: (b = 'ab'::bpchar) - -> Seq Scan on part_10_20 - Filter: (b = 'ab'::bpchar) - -> Seq Scan on part_21_30 - Filter: (b = 'ab'::bpchar) - -> Seq Scan on part_40_inf - Filter: (b = 'ab'::bpchar) -> Seq Scan on part_1_10_ab Filter: (b = 'ab'::bpchar) -> Seq Scan on part_10_20_ab @@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab'; Filter: (b = 'ab'::bpchar) -> Seq Scan on part_40_inf_ab Filter: (b = 'ab'::bpchar) -(19 rows) +(9 rows) explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab'); QUERY PLAN ----------------------------------------------------------------- Append - -> Seq Scan on range_list_parted - Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) - -> Seq Scan on part_1_10 - Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) - -> Seq Scan on part_10_20 - Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) - -> Seq Scan on part_21_30 - Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) -> Seq Scan on part_1_10_ab Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) -> Seq Scan on part_10_20_ab Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) -> Seq Scan on part_21_30_ab Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) -(15 rows) +(7 rows) /* Should select no rows because range partition key cannot be null */ explain (costs off) select * from range_list_parted where a is null; @@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null; /* Should only select rows from the null-accepting partition */ explain (costs off) select * from range_list_parted where b is null; - QUERY PLAN -------------------------------------- + QUERY PLAN +------------------------------------ Append - -> Seq Scan on range_list_parted - Filter: (b IS NULL) - -> Seq Scan on part_1_10 - Filter: (b IS NULL) - -> Seq Scan on part_10_20 - Filter: (b IS NULL) - -> Seq Scan on part_21_30 - Filter: (b IS NULL) - -> Seq Scan on part_40_inf - Filter: (b IS NULL) -> Seq Scan on part_40_inf_null Filter: (b IS NULL) -(13 rows) +(3 rows) explain (costs off) select * from range_list_parted where a is not null and a < 67; QUERY PLAN ------------------------------------------------ Append - -> Seq Scan on range_list_parted - Filter: ((a IS NOT NULL) AND (a < 67)) - -> Seq Scan on part_1_10 - Filter: ((a IS NOT NULL) AND (a < 67)) - -> Seq Scan on part_10_20 - Filter: ((a IS NOT NULL) AND (a < 67)) - -> Seq Scan on part_21_30 - Filter: ((a IS NOT NULL) AND (a < 67)) - -> Seq Scan on part_40_inf - Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_1_10_ab Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_1_10_cd @@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a < Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_40_inf_null Filter: ((a IS NOT NULL) AND (a < 67)) -(29 rows) +(19 rows) explain (costs off) select * from range_list_parted where a >= 30; - QUERY PLAN -------------------------------------- + QUERY PLAN +------------------------------------ Append - -> Seq Scan on range_list_parted - Filter: (a >= 30) - -> Seq Scan on part_40_inf - Filter: (a >= 30) -> Seq Scan on part_40_inf_ab Filter: (a >= 30) -> Seq Scan on part_40_inf_cd Filter: (a >= 30) -> Seq Scan on part_40_inf_null Filter: (a >= 30) -(11 rows) +(7 rows) drop table list_parted cascade; NOTICE: drop cascades to 3 other objects diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out index b18e420e9b..d3794140fb 100644 --- a/src/test/regress/expected/tablesample.out +++ b/src/test/regress/expected/tablesample.out @@ -322,12 +322,10 @@ explain (costs off) QUERY PLAN ------------------------------------------- Append - -> Sample Scan on parted_sample - Sampling: bernoulli ('100'::real) -> Sample Scan on parted_sample_1 Sampling: bernoulli ('100'::real) -> Sample Scan on parted_sample_2 Sampling: bernoulli ('100'::real) -(7 rows) +(5 rows) drop table parted_sample, parted_sample_1, parted_sample_2; diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index a8b7eb1c8d..04cc4ffa23 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -570,6 +570,10 @@ reset enable_bitmapscan; create table list_parted ( a varchar ) partition by list (a); + +-- test scanning partitioned table without any partitions +explain (costs off) select * from list_parted; + create table part_ab_cd partition of list_parted for values in ('ab', 'cd'); create table part_ef_gh partition of list_parted for values in ('ef', 'gh'); create table part_null_xy partition of list_parted for values in (null, 'xy'); @@ -586,6 +590,10 @@ create table range_list_parted ( b char(2) ) partition by range (a); create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b); + +-- test scanning partitioned table without any leaf partitions +explain (costs off) select * from range_list_parted; + create table part_1_10_ab partition of part_1_10 for values in ('ab'); create table part_1_10_cd partition of part_1_10 for values in ('cd'); create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b); -- 2.11.0
>From 7cb068236e7ff38599d285f10ff7445d53c2626a Mon Sep 17 00:00:00 2001 From: amit <amitlangot...@gmail.com> Date: Tue, 24 Jan 2017 14:22:34 +0900 Subject: [PATCH 3/3] Do not allocate storage for partitioned tables. Currently, it is not possible to insert any data into a partitioned table. So, they're empty at all times, which means it is wasteful to allocate relfilenode and related storage objects. --- src/backend/access/common/reloptions.c | 3 +-- src/backend/catalog/heap.c | 17 ++++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 42b4ea410f..79a75152f0 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: - case RELKIND_PARTITIONED_TABLE: options = heap_reloptions(classForm->relkind, datum, false); break; case RELKIND_VIEW: @@ -942,6 +941,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, options = index_reloptions(amoptions, datum, false); break; case RELKIND_FOREIGN_TABLE: + case RELKIND_PARTITIONED_TABLE: options = NULL; break; default: @@ -1384,7 +1384,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate) return (bytea *) rdopts; case RELKIND_RELATION: case RELKIND_MATVIEW: - case RELKIND_PARTITIONED_TABLE: return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP); default: /* other relkinds are not supported */ diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 41c0056556..2f5090b183 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -291,6 +291,7 @@ heap_create(const char *relname, case RELKIND_VIEW: case RELKIND_COMPOSITE_TYPE: case RELKIND_FOREIGN_TABLE: + case RELKIND_PARTITIONED_TABLE: create_storage = false; /* @@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname, if (oncommit != ONCOMMIT_NOOP) register_on_commit_action(relid, oncommit); - if (relpersistence == RELPERSISTENCE_UNLOGGED) - { - Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW || - relkind == RELKIND_TOASTVALUE || - relkind == RELKIND_PARTITIONED_TABLE); - + /* + * We do not want to create any storage objects for a partitioned + * table, including the init fork. + */ + if (relpersistence == RELPERSISTENCE_UNLOGGED && + relkind != RELKIND_PARTITIONED_TABLE) heap_create_init_fork(new_rel_desc); - } /* * ok, the relation has been cataloged, so close our relations and return @@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname, void heap_create_init_fork(Relation rel) { + Assert(rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_TOASTVALUE); RelationOpenSmgr(rel); smgrcreate(rel->rd_smgr, INIT_FORKNUM, false); log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM); -- 2.11.0
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers