mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Fix bitmap AND/OR scans on the inside of a nestloop partition-wise join.
reparameterize_path_by_child() failed to reparameterize BitmapAnd and BitmapOr paths. This matters only if such a path is chosen as the inside of a nestloop partition-wise join, where we have to pass in parameters from the outside of the nestloop. If that did happen, we generated a bad plan that would likely lead to crashes at execution. This is not entirely reparameterize_path_by_child()'s fault though; it's the victim of an ancient decision (my ancient decision, I think) to not bother filling in param_info in BitmapAnd/Or path nodes. That caused the function to believe that such nodes and their children contain no parameter references and so need not be processed. In hindsight that decision looks pretty penny-wise and pound-foolish: while it saves a few cycles during path node setup, we do commonly need the information later. In particular, by reversing the decision and requiring valid param_info data in all nodes of a bitmap path tree, we can get rid of indxpath.c's get_bitmap_tree_required_outer() function, which computed the data on-demand. It's not unlikely that that nets out as a savings of cycles in many scenarios. A couple of other things in indxpath.c can be simplified as well. While here, get rid of some cases in reparameterize_path_by_child() that are visibly dead or useless, given that we only care about reparameterizing paths that can be on the inside of a parameterized nestloop. This case reminds one of the maxim that untested code probably does not work, so I'm unwilling to leave unreachable code in this function. (I did leave the T_Gather case in place even though it's not reached in the regression tests. It's not very clear to me when the planner might prefer to put Gather below rather than above a nestloop, but at least in principle the case might be interesting.) Per bug #16536, originally from Arne Roland but with a test case by Andrew Gierth. Back-patch to v11 where this code came in. Discussion: https://postgr.es/m/16536-2213ee0b3aad41fd@postgresql.org
This commit is contained in:
@ -2082,3 +2082,107 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b =
|
||||
Filter: (b = 0)
|
||||
(16 rows)
|
||||
|
||||
--
|
||||
-- Test some other plan types in a partitionwise join (unfortunately,
|
||||
-- we need larger tables to get the planner to choose these plan types)
|
||||
--
|
||||
create temp table prtx1 (a integer, b integer, c integer)
|
||||
partition by range (a);
|
||||
create temp table prtx1_1 partition of prtx1 for values from (1) to (11);
|
||||
create temp table prtx1_2 partition of prtx1 for values from (11) to (21);
|
||||
create temp table prtx1_3 partition of prtx1 for values from (21) to (31);
|
||||
create temp table prtx2 (a integer, b integer, c integer)
|
||||
partition by range (a);
|
||||
create temp table prtx2_1 partition of prtx2 for values from (1) to (11);
|
||||
create temp table prtx2_2 partition of prtx2 for values from (11) to (21);
|
||||
create temp table prtx2_3 partition of prtx2 for values from (21) to (31);
|
||||
insert into prtx1 select 1 + i%30, i, i
|
||||
from generate_series(1,1000) i;
|
||||
insert into prtx2 select 1 + i%30, i, i
|
||||
from generate_series(1,500) i, generate_series(1,10) j;
|
||||
create index on prtx2 (b);
|
||||
create index on prtx2 (c);
|
||||
analyze prtx1;
|
||||
analyze prtx2;
|
||||
explain (costs off)
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and prtx2.b=prtx1.b and prtx2.c=123)
|
||||
and a<20 and c=120;
|
||||
QUERY PLAN
|
||||
-------------------------------------------------------------
|
||||
Append
|
||||
-> Nested Loop Anti Join
|
||||
-> Seq Scan on prtx1_1
|
||||
Filter: ((a < 20) AND (c = 120))
|
||||
-> Bitmap Heap Scan on prtx2_1
|
||||
Recheck Cond: ((b = prtx1_1.b) AND (c = 123))
|
||||
Filter: (a = prtx1_1.a)
|
||||
-> BitmapAnd
|
||||
-> Bitmap Index Scan on prtx2_1_b_idx
|
||||
Index Cond: (b = prtx1_1.b)
|
||||
-> Bitmap Index Scan on prtx2_1_c_idx
|
||||
Index Cond: (c = 123)
|
||||
-> Nested Loop Anti Join
|
||||
-> Seq Scan on prtx1_2
|
||||
Filter: ((a < 20) AND (c = 120))
|
||||
-> Bitmap Heap Scan on prtx2_2
|
||||
Recheck Cond: ((b = prtx1_2.b) AND (c = 123))
|
||||
Filter: (a = prtx1_2.a)
|
||||
-> BitmapAnd
|
||||
-> Bitmap Index Scan on prtx2_2_b_idx
|
||||
Index Cond: (b = prtx1_2.b)
|
||||
-> Bitmap Index Scan on prtx2_2_c_idx
|
||||
Index Cond: (c = 123)
|
||||
(23 rows)
|
||||
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and prtx2.b=prtx1.b and prtx2.c=123)
|
||||
and a<20 and c=120;
|
||||
a | b | c
|
||||
---+-----+-----
|
||||
1 | 120 | 120
|
||||
(1 row)
|
||||
|
||||
explain (costs off)
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and (prtx2.b=prtx1.b+1 or prtx2.c=99))
|
||||
and a<20 and c=91;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
Append
|
||||
-> Nested Loop Anti Join
|
||||
-> Seq Scan on prtx1_1
|
||||
Filter: ((a < 20) AND (c = 91))
|
||||
-> Bitmap Heap Scan on prtx2_1
|
||||
Recheck Cond: ((b = (prtx1_1.b + 1)) OR (c = 99))
|
||||
Filter: (a = prtx1_1.a)
|
||||
-> BitmapOr
|
||||
-> Bitmap Index Scan on prtx2_1_b_idx
|
||||
Index Cond: (b = (prtx1_1.b + 1))
|
||||
-> Bitmap Index Scan on prtx2_1_c_idx
|
||||
Index Cond: (c = 99)
|
||||
-> Nested Loop Anti Join
|
||||
-> Seq Scan on prtx1_2
|
||||
Filter: ((a < 20) AND (c = 91))
|
||||
-> Bitmap Heap Scan on prtx2_2
|
||||
Recheck Cond: ((b = (prtx1_2.b + 1)) OR (c = 99))
|
||||
Filter: (a = prtx1_2.a)
|
||||
-> BitmapOr
|
||||
-> Bitmap Index Scan on prtx2_2_b_idx
|
||||
Index Cond: (b = (prtx1_2.b + 1))
|
||||
-> Bitmap Index Scan on prtx2_2_c_idx
|
||||
Index Cond: (c = 99)
|
||||
(23 rows)
|
||||
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and (prtx2.b=prtx1.b+1 or prtx2.c=99))
|
||||
and a<20 and c=91;
|
||||
a | b | c
|
||||
---+----+----
|
||||
2 | 91 | 91
|
||||
(1 row)
|
||||
|
||||
|
@ -453,3 +453,48 @@ ANALYZE prt2;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
|
||||
|
||||
--
|
||||
-- Test some other plan types in a partitionwise join (unfortunately,
|
||||
-- we need larger tables to get the planner to choose these plan types)
|
||||
--
|
||||
create temp table prtx1 (a integer, b integer, c integer)
|
||||
partition by range (a);
|
||||
create temp table prtx1_1 partition of prtx1 for values from (1) to (11);
|
||||
create temp table prtx1_2 partition of prtx1 for values from (11) to (21);
|
||||
create temp table prtx1_3 partition of prtx1 for values from (21) to (31);
|
||||
create temp table prtx2 (a integer, b integer, c integer)
|
||||
partition by range (a);
|
||||
create temp table prtx2_1 partition of prtx2 for values from (1) to (11);
|
||||
create temp table prtx2_2 partition of prtx2 for values from (11) to (21);
|
||||
create temp table prtx2_3 partition of prtx2 for values from (21) to (31);
|
||||
insert into prtx1 select 1 + i%30, i, i
|
||||
from generate_series(1,1000) i;
|
||||
insert into prtx2 select 1 + i%30, i, i
|
||||
from generate_series(1,500) i, generate_series(1,10) j;
|
||||
create index on prtx2 (b);
|
||||
create index on prtx2 (c);
|
||||
analyze prtx1;
|
||||
analyze prtx2;
|
||||
|
||||
explain (costs off)
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and prtx2.b=prtx1.b and prtx2.c=123)
|
||||
and a<20 and c=120;
|
||||
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and prtx2.b=prtx1.b and prtx2.c=123)
|
||||
and a<20 and c=120;
|
||||
|
||||
explain (costs off)
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and (prtx2.b=prtx1.b+1 or prtx2.c=99))
|
||||
and a<20 and c=91;
|
||||
|
||||
select * from prtx1
|
||||
where not exists (select 1 from prtx2
|
||||
where prtx2.a=prtx1.a and (prtx2.b=prtx1.b+1 or prtx2.c=99))
|
||||
and a<20 and c=91;
|
||||
|
Reference in New Issue
Block a user