diff options
author | Amit Langote | 2025-02-07 08:15:09 +0000 |
---|---|---|
committer | Amit Langote | 2025-02-07 08:15:09 +0000 |
commit | cbc127917e04a978a788b8bc9d35a70244396d5b (patch) | |
tree | 9a3325897700ed0a8a57b3ef284b4ce778d1b4ff /src/test | |
parent | 926c7fce03603b49dd2529e37d47b805730584fc (diff) |
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 <[email protected]> (earlier versions)
Reviewed-by: Tomas Vondra <[email protected]>
Discussion: https://postgr.es/m/CA+HiwqFGkMSge6TgC9KQzde0ohpAycLQuV7ooitEEpbKB0O_mg@mail.gmail.com
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/regress/expected/partition_prune.out | 46 | ||||
-rw-r--r-- | src/test/regress/sql/partition_prune.sql | 20 |
2 files changed, 66 insertions, 0 deletions
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index f0707e7f7ea..e667503c961 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -4469,3 +4469,49 @@ drop table hp_contradict_test; drop operator class part_test_int4_ops2 using hash; drop operator ===(int4, int4); drop function explain_analyze(text); +-- Runtime pruning on UPDATE using WITH CHECK OPTIONS and RETURNING +create table part_abc (a int, b text, c bool) partition by list (a); +create table part_abc_1 (b text, a int, c bool); +create table part_abc_2 (a int, c bool, b text); +alter table part_abc attach partition part_abc_1 for values in (1); +alter table part_abc attach partition part_abc_2 for values in (2); +insert into part_abc values (1, 'b', true); +insert into part_abc values (2, 'c', true); +create view part_abc_view as select * from part_abc where b <> 'a' with check option; +prepare update_part_abc_view as update part_abc_view set b = $2 where a = $1 returning *; +-- Only the unpruned partition should be shown in the list of relations to be +-- updated +explain (costs off) execute update_part_abc_view (1, 'd'); + QUERY PLAN +------------------------------------------------------- + Update on part_abc + Update on part_abc_1 + -> Append + Subplans Removed: 1 + -> Seq Scan on part_abc_1 + Filter: ((b <> 'a'::text) AND (a = $1)) +(6 rows) + +execute update_part_abc_view (1, 'd'); + a | b | c +---+---+--- + 1 | d | t +(1 row) + +explain (costs off) execute update_part_abc_view (2, 'a'); + QUERY PLAN +------------------------------------------------------- + Update on part_abc + Update on part_abc_2 part_abc_1 + -> Append + Subplans Removed: 1 + -> Seq Scan on part_abc_2 part_abc_1 + Filter: ((b <> 'a'::text) AND (a = $1)) +(6 rows) + +execute update_part_abc_view (2, 'a'); +ERROR: new row violates check option for view "part_abc_view" +DETAIL: Failing row contains (2, a, t). +deallocate update_part_abc_view; +drop view part_abc_view; +drop table part_abc; diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index ea9a4fe4a23..730545e86a7 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -1354,3 +1354,23 @@ drop operator class part_test_int4_ops2 using hash; drop operator ===(int4, int4); drop function explain_analyze(text); + +-- Runtime pruning on UPDATE using WITH CHECK OPTIONS and RETURNING +create table part_abc (a int, b text, c bool) partition by list (a); +create table part_abc_1 (b text, a int, c bool); +create table part_abc_2 (a int, c bool, b text); +alter table part_abc attach partition part_abc_1 for values in (1); +alter table part_abc attach partition part_abc_2 for values in (2); +insert into part_abc values (1, 'b', true); +insert into part_abc values (2, 'c', true); +create view part_abc_view as select * from part_abc where b <> 'a' with check option; +prepare update_part_abc_view as update part_abc_view set b = $2 where a = $1 returning *; +-- Only the unpruned partition should be shown in the list of relations to be +-- updated +explain (costs off) execute update_part_abc_view (1, 'd'); +execute update_part_abc_view (1, 'd'); +explain (costs off) execute update_part_abc_view (2, 'a'); +execute update_part_abc_view (2, 'a'); +deallocate update_part_abc_view; +drop view part_abc_view; +drop table part_abc; |