mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
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 and LockRows, to avoid processing partitions pruned during initial pruning. Scan-level nodes, such as Append and MergeAppend, already avoid the unnecessary processing by accessing partition pruning results directly via part_prune_index. In contrast, top-level nodes cannot access pruning results directly and need to determine which partitions remain unpruned. To address this, this commit introduces a new bitmapset field, es_unpruned_relids, which the executor uses to track the set of unpruned relations. This field is referenced during plan initialization to skip initializing certain nodes for pruned partitions. It is initialized with PlannedStmt.unprunableRelids, a new field that the planner populates with RT indexes of relations that cannot be pruned during runtime pruning. These include relations not subject to partition pruning and those required for execution regardless of pruning. PlannedStmt.unprunableRelids is computed during set_plan_refs() by removing the RT indexes of runtime-prunable relations, identified from PartitionPruneInfos, from the full set of relation RT indexes. ExecDoInitialPruning() then updates es_unpruned_relids by adding partitions that survive initial pruning. To support this, PartitionedRelPruneInfo and PartitionedRelPruningData now include a leafpart_rti_map[] array that maps partition indexes to their corresponding RT indexes. The former is used in set_plan_refs() when constructing unprunableRelids, while the latter is used in ExecDoInitialPruning() to convert partition indexes returned by get_matching_partitions() into RT indexes, which are then added to es_unpruned_relids. These changes make it possible for ModifyTable and LockRows nodes to process only relations that remain unpruned after initial pruning. ExecInitModifyTable() trims lists, such as resultRelations, withCheckOptionLists, returningLists, and updateColnosLists, to consider only unpruned partitions. It also creates ResultRelInfo structs only for these partitions. Similarly, child RowMarks for pruned relations are skipped. By avoiding unnecessary initialization of structures for pruned partitions, these changes improve the performance of updates and deletes on partitioned tables during initial runtime pruning. Due to ExecInitModifyTable() changes as described above, EXPLAIN on a plan for UPDATE and DELETE that uses runtime initial pruning no longer lists 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
This commit is contained in:
@@ -557,6 +557,8 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
|
||||
result->planTree = top_plan;
|
||||
result->partPruneInfos = glob->partPruneInfos;
|
||||
result->rtable = glob->finalrtable;
|
||||
result->unprunableRelids = bms_difference(glob->allRelids,
|
||||
glob->prunableRelids);
|
||||
result->permInfos = glob->finalrteperminfos;
|
||||
result->resultRelations = glob->resultRelations;
|
||||
result->appendRelations = glob->appendRelations;
|
||||
|
||||
@@ -564,7 +564,9 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
|
||||
|
||||
/*
|
||||
* If it's a plain relation RTE (or a subquery that was once a view
|
||||
* reference), add the relation OID to relationOids.
|
||||
* reference), add the relation OID to relationOids. Also add its new RT
|
||||
* index to the set of relations to be potentially accessed during
|
||||
* execution.
|
||||
*
|
||||
* We do this even though the RTE might be unreferenced in the plan tree;
|
||||
* this would correspond to cases such as views that were expanded, child
|
||||
@@ -576,7 +578,11 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
|
||||
*/
|
||||
if (newrte->rtekind == RTE_RELATION ||
|
||||
(newrte->rtekind == RTE_SUBQUERY && OidIsValid(newrte->relid)))
|
||||
{
|
||||
glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
|
||||
glob->allRelids = bms_add_member(glob->allRelids,
|
||||
list_length(glob->finalrtable));
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a copy of the RTEPermissionInfo, if any, corresponding to this RTE
|
||||
@@ -1740,6 +1746,10 @@ set_customscan_references(PlannerInfo *root,
|
||||
*
|
||||
* Also update the RT indexes present in PartitionedRelPruneInfos to add the
|
||||
* offset.
|
||||
*
|
||||
* Finally, if there are initial pruning steps, add the RT indexes of the
|
||||
* leaf partitions to the set of relations that are prunable at execution
|
||||
* startup time.
|
||||
*/
|
||||
static int
|
||||
register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
|
||||
@@ -1762,6 +1772,7 @@ register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
|
||||
foreach(l2, prune_infos)
|
||||
{
|
||||
PartitionedRelPruneInfo *prelinfo = lfirst(l2);
|
||||
int i;
|
||||
|
||||
prelinfo->rtindex += rtoffset;
|
||||
prelinfo->initial_pruning_steps =
|
||||
@@ -1770,6 +1781,22 @@ register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
|
||||
prelinfo->exec_pruning_steps =
|
||||
fix_scan_list(root, prelinfo->exec_pruning_steps,
|
||||
rtoffset, 1);
|
||||
|
||||
for (i = 0; i < prelinfo->nparts; i++)
|
||||
{
|
||||
/*
|
||||
* Non-leaf partitions and partitions that do not have a
|
||||
* subplan are not included in this map as mentioned in
|
||||
* make_partitionedrel_pruneinfo().
|
||||
*/
|
||||
if (prelinfo->leafpart_rti_map[i])
|
||||
{
|
||||
prelinfo->leafpart_rti_map[i] += rtoffset;
|
||||
if (prelinfo->initial_pruning_steps)
|
||||
glob->prunableRelids = bms_add_member(glob->prunableRelids,
|
||||
prelinfo->leafpart_rti_map[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user