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

Commitcbc1279

Browse files
committed
Track unpruned relids to avoid processing pruned relations
This commit introduces changes to track unpruned relations explicitly,making it possible for top-level plan nodes, such as ModifyTable andLockRows, to avoid processing partitions pruned during initialpruning. Scan-level nodes, such as Append and MergeAppend, alreadyavoid the unnecessary processing by accessing partition pruningresults directly via part_prune_index. In contrast, top-level nodescannot access pruning results directly and need to determine whichpartitions remain unpruned.To address this, this commit introduces a new bitmapset field,es_unpruned_relids, which the executor uses to track the set ofunpruned relations. This field is referenced during planinitialization to skip initializing certain nodes for prunedpartitions. It is initialized with PlannedStmt.unprunableRelids,a new field that the planner populates with RT indexes of relationsthat cannot be pruned during runtime pruning. These include relationsnot subject to partition pruning and those required for executionregardless of pruning.PlannedStmt.unprunableRelids is computed during set_plan_refs() byremoving the RT indexes of runtime-prunable relations, identifiedfrom PartitionPruneInfos, from the full set of relation RT indexes.ExecDoInitialPruning() then updates es_unpruned_relids by addingpartitions that survive initial pruning.To support this, PartitionedRelPruneInfo and PartitionedRelPruningDatanow include a leafpart_rti_map[] array that maps partition indexes totheir corresponding RT indexes. The former is used in set_plan_refs()when constructing unprunableRelids, while the latter is used inExecDoInitialPruning() to convert partition indexes returned byget_matching_partitions() into RT indexes, which are then added toes_unpruned_relids.These changes make it possible for ModifyTable and LockRows nodes toprocess only relations that remain unpruned after initial pruning.ExecInitModifyTable() trims lists, such as resultRelations,withCheckOptionLists, returningLists, and updateColnosLists, toconsider only unpruned partitions. It also creates ResultRelInfostructs only for these partitions. Similarly, child RowMarks forpruned relations are skipped.By avoiding unnecessary initialization of structures for prunedpartitions, these changes improve the performance of updates anddeletes on partitioned tables during initial runtime pruning.Due to ExecInitModifyTable() changes as described above, EXPLAIN on aplan for UPDATE and DELETE that uses runtime initial pruning no longerlists partitions pruned during initial pruning.Reviewed-by: Robert Haas <robertmhaas@gmail.com> (earlier versions)Reviewed-by: Tomas Vondra <tomas@vondra.me>Discussion:https://postgr.es/m/CA+HiwqFGkMSge6TgC9KQzde0ohpAycLQuV7ooitEEpbKB0O_mg@mail.gmail.com
1 parent926c7fc commitcbc1279

File tree

21 files changed

+340
-51
lines changed

21 files changed

+340
-51
lines changed

‎src/backend/commands/copyfrom.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,8 @@ CopyFrom(CopyFromState cstate)
774774
* index-entry-making machinery. (There used to be a huge amount of code
775775
* here that basically duplicated execUtils.c ...)
776776
*/
777-
ExecInitRangeTable(estate,cstate->range_table,cstate->rteperminfos);
777+
ExecInitRangeTable(estate,cstate->range_table,cstate->rteperminfos,
778+
bms_make_singleton(1));
778779
resultRelInfo=target_resultRelInfo=makeNode(ResultRelInfo);
779780
ExecInitResultRelation(estate,resultRelInfo,1);
780781

‎src/backend/executor/execMain.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
851851
/*
852852
* initialize the node's execution state
853853
*/
854-
ExecInitRangeTable(estate,rangeTable,plannedstmt->permInfos);
854+
ExecInitRangeTable(estate,rangeTable,plannedstmt->permInfos,
855+
bms_copy(plannedstmt->unprunableRelids));
855856

856857
estate->es_plannedstmt=plannedstmt;
857858
estate->es_part_prune_infos=plannedstmt->partPruneInfos;
@@ -881,8 +882,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
881882
Relationrelation;
882883
ExecRowMark*erm;
883884

884-
/* ignore "parent" rowmarks; they are irrelevant at runtime */
885-
if (rc->isParent)
885+
/*
886+
* Ignore "parent" rowmarks, because they are irrelevant at
887+
* runtime. Also ignore the rowmarks belonging to child tables
888+
* that have been pruned in ExecDoInitialPruning().
889+
*/
890+
if (rc->isParent||
891+
!bms_is_member(rc->rti,estate->es_unpruned_relids))
886892
continue;
887893

888894
/* get relation's OID (will produce InvalidOid if subquery) */
@@ -2933,6 +2939,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
29332939
}
29342940
}
29352941

2942+
/*
2943+
* Copy es_unpruned_relids so that pruned relations are ignored by
2944+
* ExecInitLockRows() and ExecInitModifyTable() when initializing the plan
2945+
* trees below.
2946+
*/
2947+
rcestate->es_unpruned_relids=parentestate->es_unpruned_relids;
2948+
29362949
/*
29372950
* Initialize private state information for each SubPlan. We must do this
29382951
* before running ExecInitNode on the main query tree, since

‎src/backend/executor/execParallel.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
183183
pstmt->planTree=plan;
184184
pstmt->partPruneInfos=estate->es_part_prune_infos;
185185
pstmt->rtable=estate->es_range_table;
186+
pstmt->unprunableRelids=estate->es_unpruned_relids;
186187
pstmt->permInfos=estate->es_rteperminfos;
187188
pstmt->resultRelations=NIL;
188189
pstmt->appendRelations=NIL;

‎src/backend/executor/execPartition.c

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
182182
staticList*adjust_partition_colnos(List*colnos,ResultRelInfo*leaf_part_rri);
183183
staticList*adjust_partition_colnos_using_map(List*colnos,AttrMap*attrMap);
184184
staticPartitionPruneState*CreatePartitionPruneState(EState*estate,
185-
PartitionPruneInfo*pruneinfo);
185+
PartitionPruneInfo*pruneinfo,
186+
Bitmapset**all_leafpart_rtis);
186187
staticvoidInitPartitionPruneContext(PartitionPruneContext*context,
187188
List*pruning_steps,
188189
PartitionDescpartdesc,
@@ -196,7 +197,8 @@ static void InitExecPartitionPruneContexts(PartitionPruneState *prunstate,
196197
staticvoidfind_matching_subplans_recurse(PartitionPruningData*prunedata,
197198
PartitionedRelPruningData*pprune,
198199
boolinitial_prune,
199-
Bitmapset**validsubplans);
200+
Bitmapset**validsubplans,
201+
Bitmapset**validsubplan_rtis);
200202

201203

202204
/*
@@ -1820,9 +1822,12 @@ ExecDoInitialPruning(EState *estate)
18201822
PartitionPruneInfo*pruneinfo=lfirst_node(PartitionPruneInfo,lc);
18211823
PartitionPruneState*prunestate;
18221824
Bitmapset*validsubplans=NULL;
1825+
Bitmapset*all_leafpart_rtis=NULL;
1826+
Bitmapset*validsubplan_rtis=NULL;
18231827

18241828
/* Create and save the PartitionPruneState. */
1825-
prunestate=CreatePartitionPruneState(estate,pruneinfo);
1829+
prunestate=CreatePartitionPruneState(estate,pruneinfo,
1830+
&all_leafpart_rtis);
18261831
estate->es_part_prune_states=lappend(estate->es_part_prune_states,
18271832
prunestate);
18281833

@@ -1831,7 +1836,13 @@ ExecDoInitialPruning(EState *estate)
18311836
* bitmapset or NULL as described in the header comment.
18321837
*/
18331838
if (prunestate->do_initial_prune)
1834-
validsubplans=ExecFindMatchingSubPlans(prunestate, true);
1839+
validsubplans=ExecFindMatchingSubPlans(prunestate, true,
1840+
&validsubplan_rtis);
1841+
else
1842+
validsubplan_rtis=all_leafpart_rtis;
1843+
1844+
estate->es_unpruned_relids=bms_add_members(estate->es_unpruned_relids,
1845+
validsubplan_rtis);
18351846
estate->es_part_prune_results=lappend(estate->es_part_prune_results,
18361847
validsubplans);
18371848
}
@@ -1944,9 +1955,16 @@ ExecInitPartitionExecPruning(PlanState *planstate,
19441955
* initialized here. Those required for exec pruning are initialized later in
19451956
* ExecInitPartitionExecPruning(), as they depend on the availability of the
19461957
* parent plan node's PlanState.
1958+
*
1959+
* If initial pruning steps are to be skipped (e.g., during EXPLAIN
1960+
* (GENERIC_PLAN)), *all_leafpart_rtis will be populated with the RT indexes of
1961+
* all leaf partitions whose scanning subnode is included in the parent plan
1962+
* node's list of child plans. The caller must add these RT indexes to
1963+
* estate->es_unpruned_relids.
19471964
*/
19481965
staticPartitionPruneState*
1949-
CreatePartitionPruneState(EState*estate,PartitionPruneInfo*pruneinfo)
1966+
CreatePartitionPruneState(EState*estate,PartitionPruneInfo*pruneinfo,
1967+
Bitmapset**all_leafpart_rtis)
19501968
{
19511969
PartitionPruneState*prunestate;
19521970
intn_part_hierarchies;
@@ -2039,8 +2057,8 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo)
20392057
* The set of partitions that exist now might not be the same that
20402058
* existed when the plan was made. The normal case is that it is;
20412059
* optimize for that case with a quick comparison, and just copy
2042-
* the subplan_map and make subpart_mappoint to the one in
2043-
* PruneInfo.
2060+
* the subplan_map and make subpart_map, leafpart_rti_mappoint to
2061+
*the ones inPruneInfo.
20442062
*
20452063
* For the case where they aren't identical, we could have more
20462064
* partitions on either side; or even exactly the same number of
@@ -2059,6 +2077,7 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo)
20592077
sizeof(int)*partdesc->nparts)==0)
20602078
{
20612079
pprune->subpart_map=pinfo->subpart_map;
2080+
pprune->leafpart_rti_map=pinfo->leafpart_rti_map;
20622081
memcpy(pprune->subplan_map,pinfo->subplan_map,
20632082
sizeof(int)*pinfo->nparts);
20642083
}
@@ -2079,6 +2098,7 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo)
20792098
* mismatches.
20802099
*/
20812100
pprune->subpart_map=palloc(sizeof(int)*partdesc->nparts);
2101+
pprune->leafpart_rti_map=palloc(sizeof(int)*partdesc->nparts);
20822102

20832103
for (pp_idx=0;pp_idx<partdesc->nparts;pp_idx++)
20842104
{
@@ -2096,6 +2116,8 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo)
20962116
pinfo->subplan_map[pd_idx];
20972117
pprune->subpart_map[pp_idx]=
20982118
pinfo->subpart_map[pd_idx];
2119+
pprune->leafpart_rti_map[pp_idx]=
2120+
pinfo->leafpart_rti_map[pd_idx];
20992121
pd_idx++;
21002122
continue;
21012123
}
@@ -2133,6 +2155,7 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo)
21332155

21342156
pprune->subpart_map[pp_idx]=-1;
21352157
pprune->subplan_map[pp_idx]=-1;
2158+
pprune->leafpart_rti_map[pp_idx]=0;
21362159
}
21372160
}
21382161

@@ -2174,6 +2197,25 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo)
21742197
prunestate->execparamids=bms_add_members(prunestate->execparamids,
21752198
pinfo->execparamids);
21762199

2200+
/*
2201+
* Return all leaf partition indexes if we're skipping pruning in
2202+
* the EXPLAIN (GENERIC_PLAN) case.
2203+
*/
2204+
if (pinfo->initial_pruning_steps&& !prunestate->do_initial_prune)
2205+
{
2206+
intpart_index=-1;
2207+
2208+
while ((part_index=bms_next_member(pprune->present_parts,
2209+
part_index)) >=0)
2210+
{
2211+
Indexrtindex=pprune->leafpart_rti_map[part_index];
2212+
2213+
if (rtindex)
2214+
*all_leafpart_rtis=bms_add_member(*all_leafpart_rtis,
2215+
rtindex);
2216+
}
2217+
}
2218+
21772219
j++;
21782220
}
21792221
i++;
@@ -2439,10 +2481,15 @@ InitExecPartitionPruneContexts(PartitionPruneState *prunestate,
24392481
* Pass initial_prune if PARAM_EXEC Params cannot yet be evaluated. This
24402482
* differentiates the initial executor-time pruning step from later
24412483
* runtime pruning.
2484+
*
2485+
* The caller must pass a non-NULL validsubplan_rtis during initial pruning
2486+
* to collect the RT indexes of leaf partitions whose subnodes will be
2487+
* executed. These RT indexes are later added to EState.es_unpruned_relids.
24422488
*/
24432489
Bitmapset*
24442490
ExecFindMatchingSubPlans(PartitionPruneState*prunestate,
2445-
boolinitial_prune)
2491+
boolinitial_prune,
2492+
Bitmapset**validsubplan_rtis)
24462493
{
24472494
Bitmapset*result=NULL;
24482495
MemoryContextoldcontext;
@@ -2454,6 +2501,7 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
24542501
* evaluated *and* there are steps in which to do so.
24552502
*/
24562503
Assert(initial_prune||prunestate->do_exec_prune);
2504+
Assert(validsubplan_rtis!=NULL|| !initial_prune);
24572505

24582506
/*
24592507
* Switch to a temp context to avoid leaking memory in the executor's
@@ -2477,7 +2525,7 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
24772525
*/
24782526
pprune=&prunedata->partrelprunedata[0];
24792527
find_matching_subplans_recurse(prunedata,pprune,initial_prune,
2480-
&result);
2528+
&result,validsubplan_rtis);
24812529

24822530
/*
24832531
* Expression eval may have used space in ExprContext too. Avoid
@@ -2495,6 +2543,8 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
24952543

24962544
/* Copy result out of the temp context before we reset it */
24972545
result=bms_copy(result);
2546+
if (validsubplan_rtis)
2547+
*validsubplan_rtis=bms_copy(*validsubplan_rtis);
24982548

24992549
MemoryContextReset(prunestate->prune_context);
25002550

@@ -2505,13 +2555,16 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
25052555
* find_matching_subplans_recurse
25062556
*Recursive worker function for ExecFindMatchingSubPlans
25072557
*
2508-
* Adds valid (non-prunable) subplan IDs to *validsubplans
2558+
* Adds valid (non-prunable) subplan IDs to *validsubplans and the RT indexes
2559+
* of their corresponding leaf partitions to *validsubplan_rtis if
2560+
* it's non-NULL.
25092561
*/
25102562
staticvoid
25112563
find_matching_subplans_recurse(PartitionPruningData*prunedata,
25122564
PartitionedRelPruningData*pprune,
25132565
boolinitial_prune,
2514-
Bitmapset**validsubplans)
2566+
Bitmapset**validsubplans,
2567+
Bitmapset**validsubplan_rtis)
25152568
{
25162569
Bitmapset*partset;
25172570
inti;
@@ -2538,16 +2591,22 @@ find_matching_subplans_recurse(PartitionPruningData *prunedata,
25382591
while ((i=bms_next_member(partset,i)) >=0)
25392592
{
25402593
if (pprune->subplan_map[i] >=0)
2594+
{
25412595
*validsubplans=bms_add_member(*validsubplans,
25422596
pprune->subplan_map[i]);
2597+
if (validsubplan_rtis)
2598+
*validsubplan_rtis=bms_add_member(*validsubplan_rtis,
2599+
pprune->leafpart_rti_map[i]);
2600+
}
25432601
else
25442602
{
25452603
intpartidx=pprune->subpart_map[i];
25462604

25472605
if (partidx >=0)
25482606
find_matching_subplans_recurse(prunedata,
25492607
&prunedata->partrelprunedata[partidx],
2550-
initial_prune,validsubplans);
2608+
initial_prune,validsubplans,
2609+
validsubplan_rtis);
25512610
else
25522611
{
25532612
/*

‎src/backend/executor/execUtils.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,8 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
771771
* indexed by rangetable index.
772772
*/
773773
void
774-
ExecInitRangeTable(EState*estate,List*rangeTable,List*permInfos)
774+
ExecInitRangeTable(EState*estate,List*rangeTable,List*permInfos,
775+
Bitmapset*unpruned_relids)
775776
{
776777
/* Remember the range table List as-is */
777778
estate->es_range_table=rangeTable;
@@ -782,6 +783,15 @@ ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos)
782783
/* Set size of associated arrays */
783784
estate->es_range_table_size=list_length(rangeTable);
784785

786+
/*
787+
* Initialize the bitmapset of RT indexes (es_unpruned_relids)
788+
* representing relations that will be scanned during execution. This set
789+
* is initially populated by the caller and may be extended later by
790+
* ExecDoInitialPruning() to include RT indexes of unpruned leaf
791+
* partitions.
792+
*/
793+
estate->es_unpruned_relids=unpruned_relids;
794+
785795
/*
786796
* Allocate an array to store an open Relation corresponding to each
787797
* rangetable entry, and initialize entries to NULL. Relations are opened

‎src/backend/executor/nodeAppend.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ choose_next_subplan_locally(AppendState *node)
595595
elseif (!node->as_valid_subplans_identified)
596596
{
597597
node->as_valid_subplans=
598-
ExecFindMatchingSubPlans(node->as_prune_state, false);
598+
ExecFindMatchingSubPlans(node->as_prune_state, false,NULL);
599599
node->as_valid_subplans_identified= true;
600600
}
601601

@@ -662,7 +662,7 @@ choose_next_subplan_for_leader(AppendState *node)
662662
if (!node->as_valid_subplans_identified)
663663
{
664664
node->as_valid_subplans=
665-
ExecFindMatchingSubPlans(node->as_prune_state, false);
665+
ExecFindMatchingSubPlans(node->as_prune_state, false,NULL);
666666
node->as_valid_subplans_identified= true;
667667

668668
/*
@@ -738,7 +738,7 @@ choose_next_subplan_for_worker(AppendState *node)
738738
elseif (!node->as_valid_subplans_identified)
739739
{
740740
node->as_valid_subplans=
741-
ExecFindMatchingSubPlans(node->as_prune_state, false);
741+
ExecFindMatchingSubPlans(node->as_prune_state, false,NULL);
742742
node->as_valid_subplans_identified= true;
743743

744744
mark_invalid_subplans_as_finished(node);
@@ -891,7 +891,7 @@ ExecAppendAsyncBegin(AppendState *node)
891891
if (!node->as_valid_subplans_identified)
892892
{
893893
node->as_valid_subplans=
894-
ExecFindMatchingSubPlans(node->as_prune_state, false);
894+
ExecFindMatchingSubPlans(node->as_prune_state, false,NULL);
895895
node->as_valid_subplans_identified= true;
896896

897897
classify_matching_subplans(node);

‎src/backend/executor/nodeLockRows.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,13 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
347347
ExecRowMark*erm;
348348
ExecAuxRowMark*aerm;
349349

350-
/* ignore "parent" rowmarks; they are irrelevant at runtime */
351-
if (rc->isParent)
350+
/*
351+
* Ignore "parent" rowmarks, because they are irrelevant at runtime.
352+
* Also ignore the rowmarks belonging to child tables that have been
353+
* pruned in ExecDoInitialPruning().
354+
*/
355+
if (rc->isParent||
356+
!bms_is_member(rc->rti,estate->es_unpruned_relids))
352357
continue;
353358

354359
/* find ExecRowMark and build ExecAuxRowMark */

‎src/backend/executor/nodeMergeAppend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ ExecMergeAppend(PlanState *pstate)
233233
*/
234234
if (node->ms_valid_subplans==NULL)
235235
node->ms_valid_subplans=
236-
ExecFindMatchingSubPlans(node->ms_prune_state, false);
236+
ExecFindMatchingSubPlans(node->ms_prune_state, false,NULL);
237237

238238
/*
239239
* First time through: pull the first tuple from each valid subplan,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp