From 4a20fd84ec67fd485d8d413ca71cdb157b2e93a0 Mon Sep 17 00:00:00 2001 From: "dgrowley@gmail.com" Date: Wed, 6 Jun 2018 17:53:09 +1200 Subject: [PATCH v2] Allow direct lookups of AppendRelInfo by child relid find_appinfos_by_relids had quite a large overhead when the number of items in the append_rel_list was high. Here we're just looking for a single AppendRelInfo, so let's make an array so that can be looked up directly. A test case with 10k RANGE partitions show that planning of an UPDATE to the partitioned table is about twice as fast with this change. --- src/backend/optimizer/plan/planner.c | 4 ++++ src/backend/optimizer/prep/prepunion.c | 25 +++++++++---------------- src/backend/optimizer/util/relnode.c | 22 ++++++++++++++++++++++ src/include/nodes/relation.h | 5 +++++ 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 67a2c7a581..da112ddfd8 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1163,6 +1163,7 @@ inheritance_planner(PlannerInfo *root) List *final_rtable = NIL; int save_rel_array_size = 0; RelOptInfo **save_rel_array = NULL; + AppendRelInfo **save_append_rel_array = NULL; List *subpaths = NIL; List *subroots = NIL; List *resultRelations = NIL; @@ -1529,6 +1530,7 @@ inheritance_planner(PlannerInfo *root) } save_rel_array_size = subroot->simple_rel_array_size; save_rel_array = subroot->simple_rel_array; + save_append_rel_array = subroot->append_rel_array; /* Make sure any initplans from this rel get into the outer list */ root->init_plans = subroot->init_plans; @@ -1579,6 +1581,8 @@ inheritance_planner(PlannerInfo *root) parse->rtable = final_rtable; root->simple_rel_array_size = save_rel_array_size; root->simple_rel_array = save_rel_array; + root->append_rel_array = save_append_rel_array; + /* Must reconstruct master's simple_rte_array, too */ root->simple_rte_array = (RangeTblEntry **) palloc0((list_length(final_rtable) + 1) * sizeof(RangeTblEntry *)); diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 0ab4014be6..6047a33a44 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -2617,29 +2617,22 @@ build_child_join_sjinfo(PlannerInfo *root, SpecialJoinInfo *parent_sjinfo, AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos) { - ListCell *lc; AppendRelInfo **appinfos; int cnt = 0; - + int i; *nappinfos = bms_num_members(relids); appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos); - foreach(lc, root->append_rel_list) + Assert(root->append_rel_array); + i = -1; + while ((i = bms_next_member(relids, i)) >= 0) { - AppendRelInfo *appinfo = lfirst(lc); + AppendRelInfo *appinfo = root->append_rel_array[i]; - if (bms_is_member(appinfo->child_relid, relids)) - { - appinfos[cnt] = appinfo; - cnt++; + if (!appinfo) + elog(ERROR, "child rel missing from append_rel_array"); - /* Stop when we have gathered all the AppendRelInfos. */ - if (cnt == *nappinfos) - return appinfos; - } + appinfos[cnt++] = appinfo; } - - /* Should have found the entries ... */ - elog(ERROR, "did not find all requested child rels in append_rel_list"); - return NULL; /* not reached */ + return appinfos; } diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 82b78420e7..c27cd52f62 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -86,6 +86,28 @@ setup_simple_rel_arrays(PlannerInfo *root) root->simple_rte_array[rti++] = rte; } + + if (root->append_rel_list != NIL) + { + root->append_rel_array = (AppendRelInfo **) + palloc0(root->simple_rel_array_size * sizeof(AppendRelInfo *)); + + foreach(lc, root->append_rel_list) + { + AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc); + int child_relid = appinfo->child_relid; + + /* Sanity check */ + Assert(child_relid < root->simple_rel_array_size); + + if (root->append_rel_array[child_relid]) + elog(ERROR, "child relation already exists"); + + root->append_rel_array[child_relid] = appinfo; + } + } + else + root->append_rel_array = NULL; } /* diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 3b28d1994f..9045a90f97 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -151,6 +151,7 @@ typedef struct PlannerGlobal #define planner_subplan_get_plan(root, subplan) \ ((Plan *) list_nth((root)->glob->subplans, (subplan)->plan_id - 1)) +struct AppendRelInfo; /*---------- * PlannerInfo @@ -201,6 +202,10 @@ typedef struct PlannerInfo */ RangeTblEntry **simple_rte_array; /* rangetable as an array */ + struct AppendRelInfo **append_rel_array; /* append_rel_list indexed by + * child_relid, or NULL if + * append_rel_list is empty */ + /* * all_baserels is a Relids set of all base relids (but not "other" * relids) in the query; that is, the Relids identifier of the final join -- 2.16.2.windows.1