From 37cf419684986b919dd1d563a358dd144919132a Mon Sep 17 00:00:00 2001 From: amit Date: Fri, 15 Sep 2017 14:40:15 +0900 Subject: [PATCH 2/3] Skip scanning default partition's child tables if possible Optimize check_default_allows_bound() such that the default partition children constraints are checked against new partition constraints for implication and avoid scan of the child of which existing constraints are implied by new default partition constraints. Also, added testcase for the same. Jeevan Ladhe. --- src/backend/catalog/partition.c | 14 ++++++++++++++ src/test/regress/expected/alter_table.out | 26 ++++++++++++++++++++++++-- src/test/regress/sql/alter_table.sql | 9 +++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index 027b98d850..ea88b70a8e 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -949,7 +949,21 @@ check_default_allows_bound(Relation parent, Relation default_rel, /* Lock already taken above. */ if (part_relid != RelationGetRelid(default_rel)) + { part_rel = heap_open(part_relid, NoLock); + + /* Can we skip scanning this part_rel? */ + if (PartConstraintImpliedByRelConstraint(part_rel, + def_part_constraints)) + { + ereport(INFO, + (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints", + RelationGetRelationName(part_rel)))); + + heap_close(part_rel, NoLock); + continue; + } + } else part_rel = default_rel; diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index eaf5f4b507..3af36db779 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3346,6 +3346,18 @@ INFO: partition constraint for table "part_3_4" is implied by existing constrai ALTER TABLE list_parted2_def ADD CONSTRAINT check_a CHECK (a IN (5, 6)); CREATE TABLE part_55_66 PARTITION OF list_parted2 FOR VALUES IN (55, 66); INFO: updated partition constraint for default partition "list_parted2_def" is implied by existing constraints +-- check if default partition child relation scan skipped +DROP TABLE list_parted2_def; +CREATE TABLE list_parted2_def PARTITION OF list_parted2 DEFAULT PARTITION BY RANGE (a); +CREATE TABLE list_parted2_def_p1 PARTITION OF list_parted2_def FOR VALUES FROM (21) TO (30); +CREATE TABLE list_parted2_def_p2 PARTITION OF list_parted2_def FOR VALUES FROM (31) TO (40); +ALTER TABLE list_parted2_def_p1 ADD CONSTRAINT check_a CHECK (a IN (21, 22)); +ALTER TABLE list_parted2_def_p2 ADD CONSTRAINT check_a CHECK (a IN (31, 32)); +CREATE TABLE part_9 PARTITION OF list_parted2 FOR VALUES IN (9); +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p2" is implied by existing constraints +CREATE TABLE part_31 PARTITION OF list_parted2 FOR VALUES IN (31); +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints -- check validation when attaching range partitions CREATE TABLE range_parted ( a int, @@ -3393,18 +3405,24 @@ CREATE TABLE part_5 ( CREATE TABLE part_5_a PARTITION OF part_5 FOR VALUES IN ('a'); INSERT INTO part_5_a (a, b) VALUES (6, 'a'); ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5); +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p2" is implied by existing constraints ERROR: partition constraint is violated by some row -- delete the faulting row and also add a constraint to skip the scan DELETE FROM part_5_a WHERE a NOT IN (3); ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 5); ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5); INFO: partition constraint for table "part_5" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p2" is implied by existing constraints ALTER TABLE list_parted2 DETACH PARTITION part_5; ALTER TABLE part_5 DROP CONSTRAINT check_a; -- scan should again be skipped, even though NOT NULL is now a column property ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)), ALTER a SET NOT NULL; ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5); INFO: partition constraint for table "part_5" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p2" is implied by existing constraints -- Check the case where attnos of the partitioning columns in the table being -- attached differs from the parent. It should not affect the constraint- -- checking logic that allows to skip the scan. @@ -3416,6 +3434,8 @@ CREATE TABLE part_6 ( ALTER TABLE part_6 DROP c; ALTER TABLE list_parted2 ATTACH PARTITION part_6 FOR VALUES IN (6); INFO: partition constraint for table "part_6" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p2" is implied by existing constraints -- Similar to above, but the table being attached is a partitioned table -- whose partition has still different attnos for the root partitioning -- columns. @@ -3436,7 +3456,8 @@ ALTER TABLE part_7 ATTACH PARTITION part_7_a_null FOR VALUES IN ('a', null); INFO: partition constraint for table "part_7_a_null" is implied by existing constraints ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7); INFO: partition constraint for table "part_7" is implied by existing constraints -INFO: updated partition constraint for default partition "list_parted2_def" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p2" is implied by existing constraints -- Same example, but check this time that the constraint correctly detects -- violating rows ALTER TABLE list_parted2 DETACH PARTITION part_7; @@ -3450,7 +3471,8 @@ SELECT tableoid::regclass, a, b FROM part_7 order by a; (2 rows) ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7); -INFO: updated partition constraint for default partition "list_parted2_def" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p1" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def_p2" is implied by existing constraints ERROR: partition constraint is violated by some row -- check that leaf partitions of default partition are scanned when -- attaching a partitioned table. diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 37cca72620..3ad6302f20 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2163,6 +2163,15 @@ ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4); -- check if default partition scan skipped ALTER TABLE list_parted2_def ADD CONSTRAINT check_a CHECK (a IN (5, 6)); CREATE TABLE part_55_66 PARTITION OF list_parted2 FOR VALUES IN (55, 66); +-- check if default partition child relation scan skipped +DROP TABLE list_parted2_def; +CREATE TABLE list_parted2_def PARTITION OF list_parted2 DEFAULT PARTITION BY RANGE (a); +CREATE TABLE list_parted2_def_p1 PARTITION OF list_parted2_def FOR VALUES FROM (21) TO (30); +CREATE TABLE list_parted2_def_p2 PARTITION OF list_parted2_def FOR VALUES FROM (31) TO (40); +ALTER TABLE list_parted2_def_p1 ADD CONSTRAINT check_a CHECK (a IN (21, 22)); +ALTER TABLE list_parted2_def_p2 ADD CONSTRAINT check_a CHECK (a IN (31, 32)); +CREATE TABLE part_9 PARTITION OF list_parted2 FOR VALUES IN (9); +CREATE TABLE part_31 PARTITION OF list_parted2 FOR VALUES IN (31); -- check validation when attaching range partitions CREATE TABLE range_parted ( -- 2.11.0