mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
pg_plan_advice: Avoid miscategorizing partitionwise scans as ordinary.
Given an Append or MergeAppend node, pgpa_build_scan needs to call pgpa_make_scan for the node's own apprelids, and also for each element of child_append_relid_sets. It did that, but it overlooked the fact that the scan type applicable to the child scans might differ from the scan type applicable to the parent scan. The problem can only occur in one direction: an RTE_SUBQUERY (Merge)Append can appear on top of a RTE_RELATION (Merge)Append, but not the reverse, so the only failure mode here is to classify a partitionwise scan of a child appendrel as PGPA_SCAN_ORDINARY rather than PGPA_SCAN_PARTITIONWISE, leading to failure to include PARTITIONWISE(something) in the generated advice string. Backpatch-through: 19 Discussion: http://postgr.es/m/CA+TgmoYYHC4i-Gpzc9-JYHqih6pOK+6LTYFiNR-PioXG1nKkOQ@mail.gmail.com
This commit is contained in:
@@ -49,6 +49,24 @@ INSERT INTO ptmismatch (id, dimm, valm)
|
||||
SELECT g, 'yet another text ' || g, (g % 2) + 1
|
||||
FROM generate_series(1,3000) g;
|
||||
VACUUM ANALYZE ptmismatch;
|
||||
CREATE TABLE mllpt (a int not null, b int not null)
|
||||
PARTITION BY LIST (a);
|
||||
CREATE TABLE mllpt_a1 PARTITION OF mllpt FOR VALUES IN (1)
|
||||
PARTITION BY LIST (b);
|
||||
CREATE TABLE mllpt_a1_b1 PARTITION OF mllpt_a1 FOR VALUES IN (1)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a1_b2 PARTITION OF mllpt_a1 FOR VALUES IN (2)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a1_b3 PARTITION OF mllpt_a1 FOR VALUES IN (3)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a2 PARTITION OF mllpt FOR VALUES IN (2)
|
||||
PARTITION BY LIST (b);
|
||||
CREATE TABLE mllpt_a2_b1 PARTITION OF mllpt_a2 FOR VALUES IN (1)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a2_b2 PARTITION OF mllpt_a2 FOR VALUES IN (2)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a2_b3 PARTITION OF mllpt_a2 FOR VALUES IN (3)
|
||||
WITH (autovacuum_enabled = false);
|
||||
EXPLAIN (PLAN_ADVICE, COSTS OFF)
|
||||
SELECT * FROM pt1, pt2, pt3 WHERE pt1.id = pt2.id AND pt2.id = pt3.id
|
||||
AND val1 = 1 AND val2 = 1 AND val3 = 1;
|
||||
@@ -424,3 +442,37 @@ SELECT * FROM pt1, pt2, pt3 WHERE pt1.id = pt2.id AND pt2.id = pt3.id
|
||||
(49 rows)
|
||||
|
||||
COMMIT;
|
||||
-- We should get PARTITIONWISE advice for all unpruned partition tables.
|
||||
EXPLAIN (PLAN_ADVICE, COSTS OFF)
|
||||
SELECT * FROM mllpt WHERE a = 1 UNION ALL SELECT * FROM mllpt;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------------------
|
||||
Append
|
||||
-> Append
|
||||
-> Seq Scan on mllpt_a1_b1 mllpt_7
|
||||
Filter: (a = 1)
|
||||
-> Seq Scan on mllpt_a1_b2 mllpt_8
|
||||
Filter: (a = 1)
|
||||
-> Seq Scan on mllpt_a1_b3 mllpt_9
|
||||
Filter: (a = 1)
|
||||
-> Seq Scan on mllpt_a1_b1 mllpt
|
||||
-> Seq Scan on mllpt_a1_b2 mllpt_1
|
||||
-> Seq Scan on mllpt_a1_b3 mllpt_2
|
||||
-> Seq Scan on mllpt_a2_b1 mllpt_3
|
||||
-> Seq Scan on mllpt_a2_b2 mllpt_4
|
||||
-> Seq Scan on mllpt_a2_b3 mllpt_5
|
||||
Generated Plan Advice:
|
||||
SEQ_SCAN(mllpt/public.mllpt_a1_b1@unnamed_subquery
|
||||
mllpt/public.mllpt_a1_b2@unnamed_subquery
|
||||
mllpt/public.mllpt_a1_b3@unnamed_subquery mllpt/public.mllpt_a1_b1
|
||||
mllpt/public.mllpt_a1_b2 mllpt/public.mllpt_a1_b3 mllpt/public.mllpt_a2_b1
|
||||
mllpt/public.mllpt_a2_b2 mllpt/public.mllpt_a2_b3)
|
||||
PARTITIONWISE(mllpt mllpt/public.mllpt_a1 mllpt/public.mllpt_a2
|
||||
mllpt/public.mllpt_a1@unnamed_subquery mllpt@unnamed_subquery)
|
||||
NO_GATHER(unnamed_subquery#3 mllpt/public.mllpt_a1_b1
|
||||
mllpt/public.mllpt_a1_b2 mllpt/public.mllpt_a1_b3 mllpt/public.mllpt_a2_b1
|
||||
mllpt/public.mllpt_a2_b2 mllpt/public.mllpt_a2_b3
|
||||
mllpt/public.mllpt_a1_b1@unnamed_subquery
|
||||
mllpt/public.mllpt_a1_b2@unnamed_subquery mllpt/public.mllpt_a1_b3@unnamed_subquery)
|
||||
(27 rows)
|
||||
|
||||
|
||||
@@ -200,8 +200,13 @@ pgpa_build_scan(pgpa_plan_walker_context *walker, Plan *plan,
|
||||
child_nonjoin_relids =
|
||||
pgpa_filter_out_join_relids(child_relids,
|
||||
walker->pstmt->rtable);
|
||||
(void) pgpa_make_scan(walker, plan, strategy,
|
||||
child_nonjoin_relids);
|
||||
if (unique_nonjoin_rtekind(child_nonjoin_relids, walker->pstmt->rtable)
|
||||
== RTE_RELATION)
|
||||
(void) pgpa_make_scan(walker, plan, PGPA_SCAN_PARTITIONWISE,
|
||||
child_nonjoin_relids);
|
||||
else
|
||||
(void) pgpa_make_scan(walker, plan, PGPA_SCAN_ORDINARY,
|
||||
child_nonjoin_relids);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -54,6 +54,25 @@ INSERT INTO ptmismatch (id, dimm, valm)
|
||||
FROM generate_series(1,3000) g;
|
||||
VACUUM ANALYZE ptmismatch;
|
||||
|
||||
CREATE TABLE mllpt (a int not null, b int not null)
|
||||
PARTITION BY LIST (a);
|
||||
CREATE TABLE mllpt_a1 PARTITION OF mllpt FOR VALUES IN (1)
|
||||
PARTITION BY LIST (b);
|
||||
CREATE TABLE mllpt_a1_b1 PARTITION OF mllpt_a1 FOR VALUES IN (1)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a1_b2 PARTITION OF mllpt_a1 FOR VALUES IN (2)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a1_b3 PARTITION OF mllpt_a1 FOR VALUES IN (3)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a2 PARTITION OF mllpt FOR VALUES IN (2)
|
||||
PARTITION BY LIST (b);
|
||||
CREATE TABLE mllpt_a2_b1 PARTITION OF mllpt_a2 FOR VALUES IN (1)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a2_b2 PARTITION OF mllpt_a2 FOR VALUES IN (2)
|
||||
WITH (autovacuum_enabled = false);
|
||||
CREATE TABLE mllpt_a2_b3 PARTITION OF mllpt_a2 FOR VALUES IN (3)
|
||||
WITH (autovacuum_enabled = false);
|
||||
|
||||
EXPLAIN (PLAN_ADVICE, COSTS OFF)
|
||||
SELECT * FROM pt1, pt2, pt3 WHERE pt1.id = pt2.id AND pt2.id = pt3.id
|
||||
AND val1 = 1 AND val2 = 1 AND val3 = 1;
|
||||
@@ -100,3 +119,7 @@ EXPLAIN (PLAN_ADVICE, COSTS OFF)
|
||||
SELECT * FROM pt1, pt2, pt3 WHERE pt1.id = pt2.id AND pt2.id = pt3.id
|
||||
AND val1 = 1 AND val2 = 1 AND val3 = 1;
|
||||
COMMIT;
|
||||
|
||||
-- We should get PARTITIONWISE advice for all unpruned partition tables.
|
||||
EXPLAIN (PLAN_ADVICE, COSTS OFF)
|
||||
SELECT * FROM mllpt WHERE a = 1 UNION ALL SELECT * FROM mllpt;
|
||||
|
||||
Reference in New Issue
Block a user