Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5220bb7

Browse files
committed
Expand run-time partition pruning to work with MergeAppend
This expands the support for the run-time partition pruning which was addedfor Append in499be01 to also allow unneeded subnodes of a MergeAppendto be removed.Author: David RowleyDiscussion:https://www.postgresql.org/message-id/CAKJS1f_F_V8D7Wu-HVdnH7zCUxhoGK8XhLLtd%3DCu85qDZzXrgg%40mail.gmail.com
1 parentb33ef39 commit5220bb7

File tree

11 files changed

+356
-35
lines changed

11 files changed

+356
-35
lines changed

‎doc/src/sgml/perform.sgml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -899,12 +899,12 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000
899899
Generally, the <command>EXPLAIN</command> output will display details for
900900
every plan node which was generated by the query planner. However, there
901901
are cases where the executor is able to determine that certain nodes are
902-
not required; currently, the only nodetype to support thisis the
903-
<literal>Append</literal>node. This node type has the ability to discard
904-
subnodes which it is able todetermine won't contain any records required
905-
by the query. It is possible to determine that nodes have been removed in
906-
this way by the presence of a "Subplans Removed" property in the
907-
<command>EXPLAIN</command> output.
902+
not required; currently, the only nodetypes to support thisare the
903+
<literal>Append</literal>and <literal>MergeAppend</literal> nodes. These
904+
node types have the ability todiscard subnodes which they are able to
905+
determine won't contain any records requiredby the query. It is possible
906+
to determine that nodes have been removed inthis way by the presence of a
907+
"Subplans Removed" property in the<command>EXPLAIN</command> output.
908908
</para>
909909
</sect2>
910910

‎src/backend/executor/nodeAppend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
151151
/*
152152
* The case where no subplans survive pruning must be handled
153153
* specially. The problem here is that code in explain.c requires
154-
*an Append to have at least one subplan in order for it to
154+
*a MergeAppend to have at least one subplan in order for it to
155155
* properly determine the Vars in that subplan's targetlist. We
156156
* sidestep this issue by just initializing the first subplan and
157157
* setting as_whichplan to NO_MATCHING_SUBPLANS to indicate that

‎src/backend/executor/nodeMergeAppend.c

Lines changed: 116 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include"postgres.h"
4040

4141
#include"executor/execdebug.h"
42+
#include"executor/execPartition.h"
4243
#include"executor/nodeMergeAppend.h"
4344
#include"lib/binaryheap.h"
4445
#include"miscadmin.h"
@@ -65,8 +66,10 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
6566
{
6667
MergeAppendState*mergestate=makeNode(MergeAppendState);
6768
PlanState**mergeplanstates;
69+
Bitmapset*validsubplans;
6870
intnplans;
69-
inti;
71+
inti,
72+
j;
7073
ListCell*lc;
7174

7275
/* check for unsupported flags */
@@ -78,19 +81,80 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
7881
*/
7982
ExecLockNonLeafAppendTables(node->partitioned_rels,estate);
8083

81-
/*
82-
* Set up empty vector of subplan states
83-
*/
84-
nplans=list_length(node->mergeplans);
85-
86-
mergeplanstates= (PlanState**)palloc0(nplans*sizeof(PlanState*));
87-
8884
/*
8985
* create new MergeAppendState for our node
9086
*/
9187
mergestate->ps.plan= (Plan*)node;
9288
mergestate->ps.state=estate;
9389
mergestate->ps.ExecProcNode=ExecMergeAppend;
90+
mergestate->ms_noopscan= false;
91+
92+
/* If run-time partition pruning is enabled, then set that up now */
93+
if (node->part_prune_infos!=NIL)
94+
{
95+
PartitionPruneState*prunestate;
96+
97+
/* We may need an expression context to evaluate partition exprs */
98+
ExecAssignExprContext(estate,&mergestate->ps);
99+
100+
prunestate=ExecCreatePartitionPruneState(&mergestate->ps,
101+
node->part_prune_infos);
102+
mergestate->ms_prune_state=prunestate;
103+
104+
/* Perform an initial partition prune, if required. */
105+
if (prunestate->do_initial_prune)
106+
{
107+
/* Determine which subplans survive initial pruning */
108+
validsubplans=ExecFindInitialMatchingSubPlans(prunestate,
109+
list_length(node->mergeplans));
110+
111+
/*
112+
* The case where no subplans survive pruning must be handled
113+
* specially. The problem here is that code in explain.c requires
114+
* an Append to have at least one subplan in order for it to
115+
* properly determine the Vars in that subplan's targetlist. We
116+
* sidestep this issue by just initializing the first subplan and
117+
* setting ms_noopscan to true to indicate that we don't really
118+
* need to scan any subnodes.
119+
*/
120+
if (bms_is_empty(validsubplans))
121+
{
122+
mergestate->ms_noopscan= true;
123+
124+
/* Mark the first as valid so that it's initialized below */
125+
validsubplans=bms_make_singleton(0);
126+
}
127+
128+
nplans=bms_num_members(validsubplans);
129+
}
130+
else
131+
{
132+
/* We'll need to initialize all subplans */
133+
nplans=list_length(node->mergeplans);
134+
validsubplans=bms_add_range(NULL,0,nplans-1);
135+
}
136+
137+
/*
138+
* If no runtime pruning is required, we can fill ms_valid_subplans
139+
* immediately, preventing later calls to ExecFindMatchingSubPlans.
140+
*/
141+
if (!prunestate->do_exec_prune)
142+
mergestate->ms_valid_subplans=bms_add_range(NULL,0,nplans-1);
143+
}
144+
else
145+
{
146+
nplans=list_length(node->mergeplans);
147+
148+
/*
149+
* When run-time partition pruning is not enabled we can just mark all
150+
* subplans as valid; they must also all be initialized.
151+
*/
152+
mergestate->ms_valid_subplans=validsubplans=
153+
bms_add_range(NULL,0,nplans-1);
154+
mergestate->ms_prune_state=NULL;
155+
}
156+
157+
mergeplanstates= (PlanState**)palloc(nplans*sizeof(PlanState*));
94158
mergestate->mergeplans=mergeplanstates;
95159
mergestate->ms_nplans=nplans;
96160

@@ -101,26 +165,24 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
101165
/*
102166
* Miscellaneous initialization
103167
*
104-
* MergeAppend plans don't have expression contexts because they never
105-
* call ExecQual or ExecProject.
106-
*/
107-
108-
/*
109168
* MergeAppend nodes do have Result slots, which hold pointers to tuples,
110169
* so we have to initialize them.
111170
*/
112171
ExecInitResultTupleSlotTL(estate,&mergestate->ps);
113172

114173
/*
115-
* call ExecInitNode on each of the plans to be executed and save the
116-
* results into thearray "mergeplans".
174+
* call ExecInitNode on each of thevalidplans to be executed and save
175+
*theresults into themergeplanstates array.
117176
*/
118-
i=0;
177+
j=i=0;
119178
foreach(lc,node->mergeplans)
120179
{
121-
Plan*initNode= (Plan*)lfirst(lc);
180+
if (bms_is_member(i,validsubplans))
181+
{
182+
Plan*initNode= (Plan*)lfirst(lc);
122183

123-
mergeplanstates[i]=ExecInitNode(initNode,estate,eflags);
184+
mergeplanstates[j++]=ExecInitNode(initNode,estate,eflags);
185+
}
124186
i++;
125187
}
126188

@@ -178,11 +240,25 @@ ExecMergeAppend(PlanState *pstate)
178240

179241
if (!node->ms_initialized)
180242
{
243+
/* Nothing to do if all subplans were pruned */
244+
if (node->ms_noopscan)
245+
returnExecClearTuple(node->ps.ps_ResultTupleSlot);
246+
181247
/*
182-
* First time through: pull the first tuple from each subplan, and set
183-
* up the heap.
248+
* If we've yet to determine the valid subplans then do so now. If
249+
* run-time pruning is disabled then the valid subplans will always be
250+
* set to all subplans.
184251
*/
185-
for (i=0;i<node->ms_nplans;i++)
252+
if (node->ms_valid_subplans==NULL)
253+
node->ms_valid_subplans=
254+
ExecFindMatchingSubPlans(node->ms_prune_state);
255+
256+
/*
257+
* First time through: pull the first tuple from each valid subplan,
258+
* and set up the heap.
259+
*/
260+
i=-1;
261+
while ((i=bms_next_member(node->ms_valid_subplans,i)) >=0)
186262
{
187263
node->ms_slots[i]=ExecProcNode(node->mergeplans[i]);
188264
if (!TupIsNull(node->ms_slots[i]))
@@ -288,13 +364,32 @@ ExecEndMergeAppend(MergeAppendState *node)
288364
*/
289365
for (i=0;i<nplans;i++)
290366
ExecEndNode(mergeplans[i]);
367+
368+
/*
369+
* release any resources associated with run-time pruning
370+
*/
371+
if (node->ms_prune_state)
372+
ExecDestroyPartitionPruneState(node->ms_prune_state);
291373
}
292374

293375
void
294376
ExecReScanMergeAppend(MergeAppendState*node)
295377
{
296378
inti;
297379

380+
/*
381+
* If any PARAM_EXEC Params used in pruning expressions have changed, then
382+
* we'd better unset the valid subplans so that they are reselected for
383+
* the new parameter values.
384+
*/
385+
if (node->ms_prune_state&&
386+
bms_overlap(node->ps.chgParam,
387+
node->ms_prune_state->execparamids))
388+
{
389+
bms_free(node->ms_valid_subplans);
390+
node->ms_valid_subplans=NULL;
391+
}
392+
298393
for (i=0;i<node->ms_nplans;i++)
299394
{
300395
PlanState*subnode=node->mergeplans[i];

‎src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ _copyMergeAppend(const MergeAppend *from)
273273
COPY_POINTER_FIELD(sortOperators,from->numCols*sizeof(Oid));
274274
COPY_POINTER_FIELD(collations,from->numCols*sizeof(Oid));
275275
COPY_POINTER_FIELD(nullsFirst,from->numCols*sizeof(bool));
276+
COPY_NODE_FIELD(part_prune_infos);
276277

277278
returnnewnode;
278279
}

‎src/backend/nodes/outfuncs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ _outMergeAppend(StringInfo str, const MergeAppend *node)
434434
appendStringInfoString(str," :nullsFirst");
435435
for (i=0;i<node->numCols;i++)
436436
appendStringInfo(str," %s",booltostr(node->nullsFirst[i]));
437+
438+
WRITE_NODE_FIELD(part_prune_infos);
437439
}
438440

439441
staticvoid

‎src/backend/nodes/readfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,7 @@ _readMergeAppend(void)
16341634
READ_OID_ARRAY(sortOperators,local_node->numCols);
16351635
READ_OID_ARRAY(collations,local_node->numCols);
16361636
READ_BOOL_ARRAY(nullsFirst,local_node->numCols);
1637+
READ_NODE_FIELD(part_prune_infos);
16371638

16381639
READ_DONE();
16391640
}

‎src/backend/optimizer/plan/createplan.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,11 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
10681068
subplans=lappend(subplans,subplan);
10691069
}
10701070

1071+
/*
1072+
* If any quals exist, they may be useful to perform further partition
1073+
* pruning during execution. Gather information needed by the executor
1074+
* to do partition pruning.
1075+
*/
10711076
if (enable_partition_pruning&&
10721077
rel->reloptkind==RELOPT_BASEREL&&
10731078
best_path->partitioned_rels!=NIL)
@@ -1078,7 +1083,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
10781083

10791084
if (best_path->path.param_info)
10801085
{
1081-
10821086
List*prmquals=best_path->path.param_info->ppi_clauses;
10831087

10841088
prmquals=extract_actual_clauses(prmquals, false);
@@ -1088,12 +1092,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
10881092
prunequal=list_concat(prunequal,prmquals);
10891093
}
10901094

1091-
/*
1092-
* If any quals exist, they may be useful to perform further partition
1093-
* pruning during execution. Generate a PartitionPruneInfo for each
1094-
* partitioned rel to store these quals and allow translation of
1095-
* partition indexes into subpath indexes.
1096-
*/
10971095
if (prunequal!=NIL)
10981096
partpruneinfos=
10991097
make_partition_pruneinfo(root,
@@ -1133,6 +1131,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
11331131
List*pathkeys=best_path->path.pathkeys;
11341132
List*subplans=NIL;
11351133
ListCell*subpaths;
1134+
RelOptInfo*rel=best_path->path.parent;
1135+
List*partpruneinfos=NIL;
11361136

11371137
/*
11381138
* We don't have the actual creation of the MergeAppend node split out
@@ -1218,8 +1218,40 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
12181218
subplans=lappend(subplans,subplan);
12191219
}
12201220

1221+
/*
1222+
* If any quals exist, they may be useful to perform further partition
1223+
* pruning during execution. Gather information needed by the executor
1224+
* to do partition pruning.
1225+
*/
1226+
if (enable_partition_pruning&&
1227+
rel->reloptkind==RELOPT_BASEREL&&
1228+
best_path->partitioned_rels!=NIL)
1229+
{
1230+
List*prunequal;
1231+
1232+
prunequal=extract_actual_clauses(rel->baserestrictinfo, false);
1233+
1234+
if (best_path->path.param_info)
1235+
{
1236+
1237+
List*prmquals=best_path->path.param_info->ppi_clauses;
1238+
1239+
prmquals=extract_actual_clauses(prmquals, false);
1240+
prmquals= (List*)replace_nestloop_params(root,
1241+
(Node*)prmquals);
1242+
1243+
prunequal=list_concat(prunequal,prmquals);
1244+
}
1245+
1246+
if (prunequal!=NIL)
1247+
partpruneinfos=make_partition_pruneinfo(root,
1248+
best_path->partitioned_rels,
1249+
best_path->subpaths,prunequal);
1250+
}
1251+
12211252
node->partitioned_rels=best_path->partitioned_rels;
12221253
node->mergeplans=subplans;
1254+
node->part_prune_infos=partpruneinfos;
12231255

12241256
return (Plan*)node;
12251257
}

‎src/include/nodes/execnodes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,12 @@ struct AppendState
11061106
*slotscurrent output tuple of each subplan
11071107
*heapheap of active tuples
11081108
*initializedtrue if we have fetched first tuple from each subplan
1109+
*noopscantrue if partition pruning proved that none of the
1110+
*mergeplans can contain a record to satisfy this query.
1111+
*prune_statedetails required to allow partitions to be
1112+
*eliminated from the scan, or NULL if not possible.
1113+
*valid_subplansfor runtime pruning, valid mergeplans indexes to
1114+
*scan.
11091115
* ----------------
11101116
*/
11111117
typedefstructMergeAppendState
@@ -1118,6 +1124,9 @@ typedef struct MergeAppendState
11181124
TupleTableSlot**ms_slots;/* array of length ms_nplans */
11191125
structbinaryheap*ms_heap;/* binary heap of slot indices */
11201126
boolms_initialized;/* are subplans started? */
1127+
boolms_noopscan;
1128+
structPartitionPruneState*ms_prune_state;
1129+
Bitmapset*ms_valid_subplans;
11211130
}MergeAppendState;
11221131

11231132
/* ----------------

‎src/include/nodes/plannodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ typedef struct MergeAppend
281281
Oid*sortOperators;/* OIDs of operators to sort them by */
282282
Oid*collations;/* OIDs of collations */
283283
bool*nullsFirst;/* NULLS FIRST/LAST directions */
284+
285+
/* Info for run-time subplan pruning, one entry per partitioned_rels */
286+
List*part_prune_infos;/* List of PartitionPruneInfo */
284287
}MergeAppend;
285288

286289
/* ----------------

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp