Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7d872c9

Browse files
committed
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, as it had to trawl through the append_rel_list looking for AppendRelInfos belonging to the given childrelids. Since there can only be a single AppendRelInfo for each child rel, it seems much better to store an array in PlannerInfo which indexes these by child relid, making the function O(1) rather than O(N). This function was only called once inside the planner, so just replace that call with a lookup to the new array. find_childrel_appendrelinfo is now unused and thus removed. This fixes a planner performance regression new to v11 reported by Thomas Reiss. Author: David Rowley Reported-by: Thomas Reiss Reviewed-by: Ashutosh Bapat Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/94dd7a4b-5e50-0712-911d-2278e055c622@dalibo.com
1 parent 6ca33a8 commit 7d872c9

File tree

6 files changed

+74
-48
lines changed

6 files changed

+74
-48
lines changed

src/backend/optimizer/plan/planmain.c

+6
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ query_planner(PlannerInfo *root, List *tlist,
124124
*/
125125
setup_simple_rel_arrays(root);
126126

127+
/*
128+
* Populate append_rel_array with each AppendRelInfo to allow direct
129+
* lookups by child relid.
130+
*/
131+
setup_append_rel_array(root);
132+
127133
/*
128134
* Construct RelOptInfo nodes for all base relations in query, and
129135
* indirectly for all appendrel member relations ("other rels"). This

src/backend/optimizer/plan/planner.c

+4
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,7 @@ inheritance_planner(PlannerInfo *root)
11631163
List *final_rtable = NIL;
11641164
int save_rel_array_size = 0;
11651165
RelOptInfo **save_rel_array = NULL;
1166+
AppendRelInfo **save_append_rel_array = NULL;
11661167
List *subpaths = NIL;
11671168
List *subroots = NIL;
11681169
List *resultRelations = NIL;
@@ -1529,6 +1530,7 @@ inheritance_planner(PlannerInfo *root)
15291530
}
15301531
save_rel_array_size = subroot->simple_rel_array_size;
15311532
save_rel_array = subroot->simple_rel_array;
1533+
save_append_rel_array = subroot->append_rel_array;
15321534

15331535
/* Make sure any initplans from this rel get into the outer list */
15341536
root->init_plans = subroot->init_plans;
@@ -1579,6 +1581,8 @@ inheritance_planner(PlannerInfo *root)
15791581
parse->rtable = final_rtable;
15801582
root->simple_rel_array_size = save_rel_array_size;
15811583
root->simple_rel_array = save_rel_array;
1584+
root->append_rel_array = save_append_rel_array;
1585+
15821586
/* Must reconstruct master's simple_rte_array, too */
15831587
root->simple_rte_array = (RangeTblEntry **)
15841588
palloc0((list_length(final_rtable) + 1) * sizeof(RangeTblEntry *));

src/backend/optimizer/prep/prepunion.c

+14-15
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ plan_set_operations(PlannerInfo *root)
166166
*/
167167
setup_simple_rel_arrays(root);
168168

169+
/*
170+
* Populate append_rel_array with each AppendRelInfo to allow direct
171+
* lookups by child relid.
172+
*/
173+
setup_append_rel_array(root);
174+
169175
/*
170176
* Find the leftmost component Query. We need to use its column names for
171177
* all generated tlists (else SELECT INTO won't work right).
@@ -2617,29 +2623,22 @@ build_child_join_sjinfo(PlannerInfo *root, SpecialJoinInfo *parent_sjinfo,
26172623
AppendRelInfo **
26182624
find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
26192625
{
2620-
ListCell *lc;
26212626
AppendRelInfo **appinfos;
26222627
int cnt = 0;
2628+
int i;
26232629

26242630
*nappinfos = bms_num_members(relids);
26252631
appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
26262632

2627-
foreach(lc, root->append_rel_list)
2633+
i = -1;
2634+
while ((i = bms_next_member(relids, i)) >= 0)
26282635
{
2629-
AppendRelInfo *appinfo = lfirst(lc);
2636+
AppendRelInfo *appinfo = root->append_rel_array[i];
26302637

2631-
if (bms_is_member(appinfo->child_relid, relids))
2632-
{
2633-
appinfos[cnt] = appinfo;
2634-
cnt++;
2638+
if (!appinfo)
2639+
elog(ERROR, "child rel %d not found in append_rel_array", i);
26352640

2636-
/* Stop when we have gathered all the AppendRelInfos. */
2637-
if (cnt == *nappinfos)
2638-
return appinfos;
2639-
}
2641+
appinfos[cnt++] = appinfo;
26402642
}
2641-
2642-
/* Should have found the entries ... */
2643-
elog(ERROR, "did not find all requested child rels in append_rel_list");
2644-
return NULL; /* not reached */
2643+
return appinfos;
26452644
}

src/backend/optimizer/util/relnode.c

+39-31
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,43 @@ setup_simple_rel_arrays(PlannerInfo *root)
8888
}
8989
}
9090

91+
/*
92+
* setup_append_rel_array
93+
* Populate the append_rel_array to allow direct lookups of
94+
* AppendRelInfos by child relid.
95+
*
96+
* The array remains unallocated if there are no AppendRelInfos.
97+
*/
98+
void
99+
setup_append_rel_array(PlannerInfo *root)
100+
{
101+
ListCell *lc;
102+
int size = list_length(root->parse->rtable) + 1;
103+
104+
if (root->append_rel_list == NIL)
105+
{
106+
root->append_rel_array = NULL;
107+
return;
108+
}
109+
110+
root->append_rel_array = (AppendRelInfo **)
111+
palloc0(size * sizeof(AppendRelInfo *));
112+
113+
foreach(lc, root->append_rel_list)
114+
{
115+
AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
116+
int child_relid = appinfo->child_relid;
117+
118+
/* Sanity check */
119+
Assert(child_relid < size);
120+
121+
if (root->append_rel_array[child_relid])
122+
elog(ERROR, "child relation already exists");
123+
124+
root->append_rel_array[child_relid] = appinfo;
125+
}
126+
}
127+
91128
/*
92129
* build_simple_rel
93130
* Construct a new RelOptInfo for a base relation or 'other' relation.
@@ -1184,36 +1221,6 @@ fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
11841221
}
11851222

11861223

1187-
/*
1188-
* find_childrel_appendrelinfo
1189-
* Get the AppendRelInfo associated with an appendrel child rel.
1190-
*
1191-
* This search could be eliminated by storing a link in child RelOptInfos,
1192-
* but for now it doesn't seem performance-critical. (Also, it might be
1193-
* difficult to maintain such a link during mutation of the append_rel_list.)
1194-
*/
1195-
AppendRelInfo *
1196-
find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel)
1197-
{
1198-
Index relid = rel->relid;
1199-
ListCell *lc;
1200-
1201-
/* Should only be called on child rels */
1202-
Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
1203-
1204-
foreach(lc, root->append_rel_list)
1205-
{
1206-
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
1207-
1208-
if (appinfo->child_relid == relid)
1209-
return appinfo;
1210-
}
1211-
/* should have found the entry ... */
1212-
elog(ERROR, "child rel %d not found in append_rel_list", relid);
1213-
return NULL; /* not reached */
1214-
}
1215-
1216-
12171224
/*
12181225
* find_childrel_parents
12191226
* Compute the set of parent relids of an appendrel child rel.
@@ -1228,10 +1235,11 @@ find_childrel_parents(PlannerInfo *root, RelOptInfo *rel)
12281235
Relids result = NULL;
12291236

12301237
Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
1238+
Assert(rel->relid > 0 && rel->relid < root->simple_rel_array_size);
12311239

12321240
do
12331241
{
1234-
AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel);
1242+
AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
12351243
Index prelid = appinfo->parent_relid;
12361244

12371245
result = bms_add_member(result, prelid);

src/include/nodes/relation.h

+10
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ typedef struct PlannerGlobal
162162
* the passed-in Query data structure; someday that should stop.
163163
*----------
164164
*/
165+
struct AppendRelInfo;
166+
165167
typedef struct PlannerInfo
166168
{
167169
NodeTag type;
@@ -201,6 +203,14 @@ typedef struct PlannerInfo
201203
*/
202204
RangeTblEntry **simple_rte_array; /* rangetable as an array */
203205

206+
/*
207+
* append_rel_list is the same length as the above arrays, and holds
208+
* pointers to the corresponding AppendRelInfo entry indexed by
209+
* child_relid, or NULL if none. The array itself is not allocated if
210+
* append_rel_list is empty.
211+
*/
212+
struct AppendRelInfo **append_rel_array;
213+
204214
/*
205215
* all_baserels is a Relids set of all base relids (but not "other"
206216
* relids) in the query; that is, the Relids identifier of the final join

src/include/optimizer/pathnode.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ extern Path *reparameterize_path_by_child(PlannerInfo *root, Path *path,
261261
* prototypes for relnode.c
262262
*/
263263
extern void setup_simple_rel_arrays(PlannerInfo *root);
264+
extern void setup_append_rel_array(PlannerInfo *root);
264265
extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
265266
RelOptInfo *parent);
266267
extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
@@ -278,8 +279,6 @@ extern Relids min_join_parameterization(PlannerInfo *root,
278279
extern RelOptInfo *build_empty_join_rel(PlannerInfo *root);
279280
extern RelOptInfo *fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind,
280281
Relids relids);
281-
extern AppendRelInfo *find_childrel_appendrelinfo(PlannerInfo *root,
282-
RelOptInfo *rel);
283282
extern Relids find_childrel_parents(PlannerInfo *root, RelOptInfo *rel);
284283
extern ParamPathInfo *get_baserel_parampathinfo(PlannerInfo *root,
285284
RelOptInfo *baserel,

0 commit comments

Comments
 (0)