From a4b21ab6fd0fd57902f5471ec962a77b59085158 Mon Sep 17 00:00:00 2001 From: Andy Fan Date: Wed, 2 Feb 2022 11:59:53 +0800 Subject: [PATCH v2 6/6] Added the testcase for this feature and fix the previous test case as well. The new added test case needs outputting some runtime statistics, which probably be different at each run. I can think of a way to make the test case stable if the patchsets is not wrong at the first step. --- .../postgres_fdw/expected/postgres_fdw.out | 15 +- src/test/regress/expected/ec_filter.out | 137 ++++++++++++++++++ src/test/regress/expected/equivclass.out | 38 ++--- src/test/regress/expected/join.out | 43 +++--- src/test/regress/expected/partition_join.out | 54 ++++--- src/test/regress/expected/partition_prune.out | 56 +------ src/test/regress/sql/ec_filter.sql | 46 ++++++ 7 files changed, 267 insertions(+), 122 deletions(-) create mode 100644 src/test/regress/expected/ec_filter.out create mode 100644 src/test/regress/sql/ec_filter.sql diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index d89fd4e11ab..41d0cd414cd 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -2335,13 +2335,16 @@ SELECT ft4.c1, q.* FROM ft4 LEFT JOIN (SELECT 13, ft1.c1, ft2.c1 FROM ft1 RIGHT UPDATE ft5 SET c3 = null where c1 % 9 = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT ft5, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2 FROM ft5 left join ft4 on ft5.c1 = ft4.c1 WHERE ft4.c1 BETWEEN 10 and 30 ORDER BY ft5.c1, ft4.c1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Sort Output: ft5.*, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2 - Relations: (public.ft5) INNER JOIN (public.ft4) - Remote SQL: SELECT CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1.c1, r1.c2, r1.c3) END, r1.c1, r1.c2, r1.c3, r2.c1, r2.c2 FROM ("S 1"."T 4" r1 INNER JOIN "S 1"."T 3" r2 ON (((r1.c1 = r2.c1)) AND ((r2.c1 >= 10)) AND ((r2.c1 <= 30)) AND ((r1.c1 >= 10)) AND ((r1.c1 <= 30)))) ORDER BY r1.c1 ASC NULLS LAST -(4 rows) + Sort Key: ft5.c1 + -> Foreign Scan + Output: ft5.*, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2 + Relations: (public.ft5) INNER JOIN (public.ft4) + Remote SQL: SELECT CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1.c1, r1.c2, r1.c3) END, r1.c1, r1.c2, r1.c3, r2.c1, r2.c2 FROM ("S 1"."T 4" r1 INNER JOIN "S 1"."T 3" r2 ON (((r1.c1 = r2.c1)) AND ((r2.c1 >= 10)) AND ((r2.c1 <= 30)) AND ((r1.c1 >= 10)) AND ((r1.c1 <= 30)))) +(7 rows) SELECT ft5, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2 FROM ft5 left join ft4 on ft5.c1 = ft4.c1 WHERE ft4.c1 BETWEEN 10 and 30 ORDER BY ft5.c1, ft4.c1; ft5 | c1 | c2 | c3 | c1 | c2 diff --git a/src/test/regress/expected/ec_filter.out b/src/test/regress/expected/ec_filter.out new file mode 100644 index 00000000000..2ee670af1ec --- /dev/null +++ b/src/test/regress/expected/ec_filter.out @@ -0,0 +1,137 @@ +-- THIS TEST IS JUST FOW REVIEW PURPOSE, IT CONTAINS TOO MANY RUNTIME STATS. +set enable_hashjoin to off; +set enable_mergejoin to off; +set enable_seqscan to on; +-- 1. The joinrel.rows should be correct. +-- 2. The path estimated rows for b should be correct. +-- 3. the estimated rows from a in wrong, but that is not the fault of this patch. +explain analyze select * from tenk1 a, tenk1 b where a.thousand = b.thousand and a.thousand < 100; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Nested Loop (cost=24.90..459.16 rows=10740 width=488) (actual time=0.418..15.061 rows=10000 loops=1) + -> Bitmap Heap Scan on tenk1 b (cost=24.61..383.03 rows=1074 width=244) (actual time=0.368..1.427 rows=1000 loops=1) + Recheck Cond: (thousand < 100) + Heap Blocks: exact=324 + -> Bitmap Index Scan on tenk1_thous_tenthous (cost=0.00..24.34 rows=1074 width=0) (actual time=0.256..0.257 rows=1000 loops=1) + Index Cond: (thousand < 100) + -> Memoize (cost=0.30..0.47 rows=1 width=244) (actual time=0.002..0.006 rows=10 loops=1000) + Cache Key: b.thousand + Cache Mode: logical + Hits: 900 Misses: 100 Evictions: 0 Overflows: 0 Memory Usage: 277kB + -> Index Scan using tenk1_thous_tenthous on tenk1 a (cost=0.29..0.46 rows=1 width=244) (actual time=0.010..0.030 rows=10 loops=100) + Index Cond: ((thousand = b.thousand) AND (thousand < 100)) + Planning Time: 2.314 ms + Execution Time: 16.022 ms +(14 rows) + +create table d_tenk2 as select * from tenk1 union all select * from tenk1; +create index on d_tenk2(thousand); +analyze d_tenk2 ; +set enable_seqscan to off; +drop index tenk1_thous_tenthous; +-- 1. The parameterized path of b shows the correct rows estimation as well. +-- 2. The new added qual is fully duplicated with the join clause, so it should be removed. +explain analyze select * from tenk1 a join d_tenk2 b on a.thousand = b.thousand and a.thousand < 100; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- + Nested Loop (cost=10000000000.30..10000002799.78 rows=20020 width=488) (actual time=0.045..26.640 rows=20000 loops=1) + -> Seq Scan on tenk1 a (cost=10000000000.00..10000000470.00 rows=1001 width=244) (actual time=0.015..3.923 rows=1000 loops=1) + Filter: (thousand < 100) + Rows Removed by Filter: 9000 + -> Memoize (cost=0.30..3.18 rows=20 width=244) (actual time=0.002..0.008 rows=20 loops=1000) + Cache Key: a.thousand + Cache Mode: logical + Hits: 900 Misses: 100 Evictions: 0 Overflows: 0 Memory Usage: 546kB + -> Index Scan using d_tenk2_thousand_idx on d_tenk2 b (cost=0.29..3.17 rows=20 width=244) (actual time=0.008..0.038 rows=20 loops=100) + Index Cond: (thousand = a.thousand) + Planning Time: 0.829 ms + Execution Time: 28.033 ms +(12 rows) + +create index tenk1_thous_tenthous on tenk1(thousand, tenthous); +-- test ef filter with partition prune. +create table p (a int, b int) partition by range(a); +select 'create table p_' || i || ' partition of p for values from (' || (i-1) * 100000 || ') to (' || i * 100000 || ');' from generate_series(1, 5)i; \gexec + ?column? +------------------------------------------------------------------------ + create table p_1 partition of p for values from (0) to (100000); + create table p_2 partition of p for values from (100000) to (200000); + create table p_3 partition of p for values from (200000) to (300000); + create table p_4 partition of p for values from (300000) to (400000); + create table p_5 partition of p for values from (400000) to (500000); +(5 rows) + +create table p_1 partition of p for values from (0) to (100000); +create table p_2 partition of p for values from (100000) to (200000); +create table p_3 partition of p for values from (200000) to (300000); +create table p_4 partition of p for values from (300000) to (400000); +create table p_5 partition of p for values from (400000) to (500000); +insert into p select i, i from generate_series(1, 5 * 100000 -1) i; +create table q (a int, b int) partition by range(a); +select 'create table q_' || i || ' partition of q for values from (' || (i-1) * 100000 || ') to (' || i * 100000 || ');' from generate_series(1, 5)i; \gexec + ?column? +------------------------------------------------------------------------ + create table q_1 partition of q for values from (0) to (100000); + create table q_2 partition of q for values from (100000) to (200000); + create table q_3 partition of q for values from (200000) to (300000); + create table q_4 partition of q for values from (300000) to (400000); + create table q_5 partition of q for values from (400000) to (500000); +(5 rows) + +create table q_1 partition of q for values from (0) to (100000); +create table q_2 partition of q for values from (100000) to (200000); +create table q_3 partition of q for values from (200000) to (300000); +create table q_4 partition of q for values from (300000) to (400000); +create table q_5 partition of q for values from (400000) to (500000); +insert into q select * from p; +create index on q(a); +select * from p, q where p.a = q.a and p.a > 5 * 100000 - 3; + a | b | a | b +--------+--------+--------+-------- + 499998 | 499998 | 499998 | 499998 + 499999 | 499999 | 499999 | 499999 +(2 rows) + +set plan_cache_mode to force_generic_plan ; +prepare s as select * from p, q where p.a = q.a and p.a > $1; +explain (costs off) execute s(5 * 100000 - 3); + QUERY PLAN +--------------------------------------------------- + Nested Loop + -> Append + Subplans Removed: 4 + -> Seq Scan on p_5 p_1 + Filter: (a > $1) + -> Append + Subplans Removed: 4 + -> Index Scan using q_5_a_idx on q_5 q_1 + Index Cond: (a = p.a) +(9 rows) + +-- support perudo const. +prepare s2 as select * from p, q where p.a = q.a and p.a > abs($1::integer); +explain (costs off) execute s2(5 * 100000 - 3); + QUERY PLAN +--------------------------------------------------- + Nested Loop + -> Append + Subplans Removed: 4 + -> Seq Scan on p_5 p_1 + Filter: (a > abs($1)) + -> Append + Subplans Removed: 4 + -> Index Scan using q_5_a_idx on q_5 q_1 + Index Cond: (a = p.a) +(9 rows) + +-- test the IN Expr. +explain (costs off) select * from p, q where p.a = q.a and p.a in (30, 5000000 -3); + QUERY PLAN +------------------------------------------------------- + Nested Loop + -> Seq Scan on p_1 p + Filter: (a = ANY ('{30,4999997}'::integer[])) + -> Index Scan using q_1_a_idx on q_1 q + Index Cond: (a = p.a) +(5 rows) + diff --git a/src/test/regress/expected/equivclass.out b/src/test/regress/expected/equivclass.out index 92fcec1158b..a5042c3cbc3 100644 --- a/src/test/regress/expected/equivclass.out +++ b/src/test/regress/expected/equivclass.out @@ -407,14 +407,14 @@ set session authorization regress_user_ectest; explain (costs off) select * from ec0 a, ec1 b where a.ff = b.ff and a.ff = 43::bigint::int8alias1; - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------- Nested Loop -> Index Scan using ec0_pkey on ec0 a Index Cond: (ff = '43'::int8alias1) -> Index Scan using ec1_pkey on ec1 b Index Cond: (ff = a.ff) - Filter: ((f1 < '5'::int8alias1) AND (ff = '43'::int8alias1)) + Filter: (f1 < '5'::int8alias1) (6 rows) reset session authorization; @@ -456,37 +456,29 @@ explain (costs off) select * from ec0 inner join ec1 on ec0.ff = ec1.ff where ec0.ff between 1 and 10; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Nested Loop - Join Filter: (ec0.ff = ec1.ff) - -> Bitmap Heap Scan on ec0 + -> Bitmap Heap Scan on ec1 Recheck Cond: ((ff >= 1) AND (ff <= 10)) - -> Bitmap Index Scan on ec0_pkey + -> Bitmap Index Scan on ec1_pkey Index Cond: ((ff >= 1) AND (ff <= 10)) - -> Materialize - -> Bitmap Heap Scan on ec1 - Recheck Cond: ((ff >= 1) AND (ff <= 10)) - -> Bitmap Index Scan on ec1_pkey - Index Cond: ((ff >= 1) AND (ff <= 10)) -(11 rows) + -> Index Scan using ec0_pkey on ec0 + Index Cond: ((ff = ec1.ff) AND (ff >= 1) AND (ff <= 10)) +(7 rows) explain (costs off) select * from ec0 inner join ec1 on ec0.ff = ec1.ff where ec1.ff between 1 and 10; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Nested Loop - Join Filter: (ec0.ff = ec1.ff) -> Bitmap Heap Scan on ec0 Recheck Cond: ((ff >= 1) AND (ff <= 10)) -> Bitmap Index Scan on ec0_pkey Index Cond: ((ff >= 1) AND (ff <= 10)) - -> Materialize - -> Bitmap Heap Scan on ec1 - Recheck Cond: ((ff >= 1) AND (ff <= 10)) - -> Bitmap Index Scan on ec1_pkey - Index Cond: ((ff >= 1) AND (ff <= 10)) -(11 rows) + -> Index Scan using ec1_pkey on ec1 + Index Cond: ((ff = ec0.ff) AND (ff >= 1) AND (ff <= 10)) +(7 rows) diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index b20de6a505f..7df4f93856e 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -6496,9 +6496,10 @@ where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 = any (array[1]); Merge Cond: (j1.id1 = j2.id1) Join Filter: (j1.id2 = j2.id2) -> Index Scan using j1_id1_idx on j1 + Index Cond: (id1 = ANY ('{1}'::integer[])) -> Index Scan using j2_id1_idx on j2 Index Cond: (id1 = ANY ('{1}'::integer[])) -(6 rows) +(7 rows) select * from j1 inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2 @@ -6513,16 +6514,17 @@ where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 = any (array[1]); explain (costs off) select * from j1 inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2 where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 >= any (array[1,5]); - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------- Merge Join - Merge Cond: (j1.id1 = j2.id1) - Join Filter: (j1.id2 = j2.id2) - -> Index Scan using j1_id1_idx on j1 + Merge Cond: ((j1.id1 = j2.id1) AND (j1.id2 = j2.id2)) + -> Index Only Scan using j1_pkey on j1 + Index Cond: (id1 >= ANY ('{1,5}'::integer[])) + Filter: ((id1 % 1000) = 1) -> Index Only Scan using j2_pkey on j2 Index Cond: (id1 >= ANY ('{1,5}'::integer[])) Filter: ((id1 % 1000) = 1) -(7 rows) +(8 rows) select * from j1 inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2 @@ -6550,22 +6552,24 @@ where exists (select 1 from tenk1 t3 --------------------------------------------------------------------------------- Nested Loop Output: t1.unique1, t2.hundred - -> Nested Loop + -> Hash Join Output: t1.unique1, t3.tenthous - Join Filter: (t1.unique1 = t3.thousand) - -> Index Only Scan using onek_unique1 on public.onek t1 - Output: t1.unique1 - Index Cond: (t1.unique1 < 1) + Hash Cond: (t3.thousand = t1.unique1) -> HashAggregate Output: t3.thousand, t3.tenthous Group Key: t3.thousand, t3.tenthous -> Index Only Scan using tenk1_thous_tenthous on public.tenk1 t3 Output: t3.thousand, t3.tenthous Index Cond: (t3.thousand < 1) + -> Hash + Output: t1.unique1 + -> Index Only Scan using onek_unique1 on public.onek t1 + Output: t1.unique1 + Index Cond: (t1.unique1 < 1) -> Index Only Scan using tenk1_hundred on public.tenk1 t2 Output: t2.hundred Index Cond: (t2.hundred = t3.tenthous) -(17 rows) +(19 rows) -- ... unless it actually is unique create table j3 as select unique1, tenthous from onek; @@ -6577,22 +6581,21 @@ from onek t1, tenk1 t2 where exists (select 1 from j3 where j3.unique1 = t1.unique1 and j3.tenthous = t2.hundred) and t1.unique1 < 1; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------- Nested Loop Output: t1.unique1, t2.hundred -> Nested Loop Output: t1.unique1, j3.tenthous - Join Filter: (t1.unique1 = j3.unique1) - -> Index Only Scan using onek_unique1 on public.onek t1 - Output: t1.unique1 - Index Cond: (t1.unique1 < 1) -> Index Only Scan using j3_unique1_tenthous_idx on public.j3 Output: j3.unique1, j3.tenthous Index Cond: (j3.unique1 < 1) + -> Index Only Scan using onek_unique1 on public.onek t1 + Output: t1.unique1 + Index Cond: ((t1.unique1 = j3.unique1) AND (t1.unique1 < 1)) -> Index Only Scan using tenk1_hundred on public.tenk1 t2 Output: t2.hundred Index Cond: (t2.hundred = j3.tenthous) -(14 rows) +(13 rows) drop table j3; diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out index 5a2923bac6c..c12351a3b0a 100644 --- a/src/test/regress/expected/partition_join.out +++ b/src/test/regress/expected/partition_join.out @@ -4449,16 +4449,18 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -> Hash Join Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c)) -> Seq Scan on plt2_adv_p3 t2_1 + Filter: (c = ANY ('{0003,0004,0005}'::text[])) -> Hash -> Seq Scan on plt1_adv_p3 t1_1 Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[]))) -> Hash Join Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c)) -> Seq Scan on plt2_adv_p4 t2_2 + Filter: (c = ANY ('{0003,0004,0005}'::text[])) -> Hash -> Seq Scan on plt1_adv_p4 t1_2 Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[]))) -(15 rows) +(17 rows) SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IN ('0003', '0004', '0005') AND t1.b < 10 ORDER BY t1.a; a | c | a | c @@ -4502,16 +4504,18 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -> Hash Join Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c)) -> Seq Scan on plt2_adv_p3 t2_1 + Filter: (c = ANY ('{0003,0004,0005}'::text[])) -> Hash -> Seq Scan on plt1_adv_p3 t1_1 Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[]))) -> Hash Join Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c)) -> Seq Scan on plt2_adv_p4 t2_2 + Filter: (c = ANY ('{0003,0004,0005}'::text[])) -> Hash -> Seq Scan on plt1_adv_p4 t1_2 Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[]))) -(15 rows) +(17 rows) SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IN ('0003', '0004', '0005') AND t1.b < 10 ORDER BY t1.a; a | c | a | c @@ -4771,8 +4775,8 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2 EXPLAIN (COSTS OFF) SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b, t2.b; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: t1.a, t1.b, t2.b -> Append @@ -4786,21 +4790,21 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2 -> Hash -> Append -> Seq Scan on beta_neg_p1 t2_2 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Seq Scan on beta_neg_p2 t2_3 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Nested Loop Join Filter: ((t1_4.a = t2_4.a) AND (t1_4.c = t2_4.c)) -> Seq Scan on alpha_pos_p2 t1_4 Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Seq Scan on beta_pos_p2 t2_4 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Nested Loop Join Filter: ((t1_5.a = t2_5.a) AND (t1_5.c = t2_5.c)) -> Seq Scan on alpha_pos_p3 t1_5 Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Seq Scan on beta_pos_p3 t2_5 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) (28 rows) SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b, t2.b; @@ -4826,38 +4830,40 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2 EXPLAIN (COSTS OFF) SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: t1.a, t1.b -> Append - -> Hash Join - Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c)) - -> Seq Scan on alpha_neg_p1 t1_1 - Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) - -> Hash + -> Merge Join + Merge Cond: ((t1_1.a = t2_1.a) AND (t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c)) + -> Sort + Sort Key: t1_1.a, t1_1.b, t1_1.c + -> Seq Scan on alpha_neg_p1 t1_1 + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) + -> Sort + Sort Key: t2_1.a, t2_1.b, t2_1.c -> Seq Scan on beta_neg_p1 t2_1 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) - -> Hash Join - Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c)) + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) + -> Nested Loop + Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c)) + -> Seq Scan on beta_neg_p2 t2_2 + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Seq Scan on alpha_neg_p2 t1_2 Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) - -> Hash - -> Seq Scan on beta_neg_p2 t2_2 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) -> Nested Loop Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.b = t2_3.b) AND (t1_3.c = t2_3.c)) -> Seq Scan on alpha_pos_p2 t1_3 Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Seq Scan on beta_pos_p2 t2_3 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Nested Loop Join Filter: ((t1_4.a = t2_4.a) AND (t1_4.b = t2_4.b) AND (t1_4.c = t2_4.c)) -> Seq Scan on alpha_pos_p3 t1_4 Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) -> Seq Scan on beta_pos_p3 t2_4 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) -(29 rows) + Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))) +(31 rows) SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b; a | b | c | a | b | c diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 7555764c779..3fb515cdd9d 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -2104,19 +2104,7 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 ab_3 (actual rows=N loops=N) Index Cond: (a = a.a) - -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 ab_4 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 ab_5 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b3_a_idx on ab_a2_b3 ab_6 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 ab_7 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 ab_8 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 ab_9 (never executed) - Index Cond: (a = a.a) -(27 rows) +(15 rows) -- Ensure the same partitions are pruned when we make the nested loop -- parameter an Expr rather than a plain Param. @@ -2171,19 +2159,13 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 ab_3 (actual rows=N loops=N) Index Cond: (a = a.a) - -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 ab_4 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 ab_5 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b3_a_idx on ab_a2_b3 ab_6 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 ab_7 (actual rows=N loops=N) + -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 ab_4 (actual rows=N loops=N) Index Cond: (a = a.a) - -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 ab_8 (actual rows=N loops=N) + -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 ab_5 (actual rows=N loops=N) Index Cond: (a = a.a) - -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 ab_9 (actual rows=N loops=N) + -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 ab_6 (actual rows=N loops=N) Index Cond: (a = a.a) -(27 rows) +(21 rows) select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 0)'); explain_parallel_append @@ -2204,19 +2186,7 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 ab_3 (actual rows=N loops=N) Index Cond: (a = a.a) - -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 ab_4 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 ab_5 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b3_a_idx on ab_a2_b3 ab_6 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 ab_7 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 ab_8 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 ab_9 (never executed) - Index Cond: (a = a.a) -(28 rows) +(16 rows) delete from lprt_a where a = 1; select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 0)'); @@ -2238,19 +2208,7 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 ab_3 (never executed) Index Cond: (a = a.a) - -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 ab_4 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 ab_5 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a2_b3_a_idx on ab_a2_b3 ab_6 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 ab_7 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 ab_8 (never executed) - Index Cond: (a = a.a) - -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 ab_9 (never executed) - Index Cond: (a = a.a) -(28 rows) +(16 rows) reset enable_hashjoin; reset enable_mergejoin; diff --git a/src/test/regress/sql/ec_filter.sql b/src/test/regress/sql/ec_filter.sql new file mode 100644 index 00000000000..f79e4206c50 --- /dev/null +++ b/src/test/regress/sql/ec_filter.sql @@ -0,0 +1,46 @@ +-- THIS TEST IS JUST FOW REVIEW PURPOSE, IT CONTAINS TOO MANY RUNTIME STATS. +set enable_hashjoin to off; +set enable_mergejoin to off; +set enable_seqscan to on; +-- 1. The joinrel.rows should be correct. +-- 2. The path estimated rows for b should be correct. +-- 3. the estimated rows from a in wrong, but that is not the fault of this patch. +explain analyze select * from tenk1 a, tenk1 b where a.thousand = b.thousand and a.thousand < 100; + +create table d_tenk2 as select * from tenk1 union all select * from tenk1; +create index on d_tenk2(thousand); +analyze d_tenk2 ; + +set enable_seqscan to off; +drop index tenk1_thous_tenthous; +-- 1. The parameterized path of b shows the correct rows estimation as well. +-- 2. The new added qual is fully duplicated with the join clause, so it should be removed. +explain analyze select * from tenk1 a join d_tenk2 b on a.thousand = b.thousand and a.thousand < 100; + +create index tenk1_thous_tenthous on tenk1(thousand, tenthous); + +-- test ef filter with partition prune. + +create table p (a int, b int) partition by range(a); +select 'create table p_' || i || ' partition of p for values from (' || (i-1) * 100000 || ') to (' || i * 100000 || ');' from generate_series(1, 5)i; \gexec +insert into p select i, i from generate_series(1, 5 * 100000 -1) i; + +create table q (a int, b int) partition by range(a); +select 'create table q_' || i || ' partition of q for values from (' || (i-1) * 100000 || ') to (' || i * 100000 || ');' from generate_series(1, 5)i; \gexec +insert into q select * from p; +create index on q(a); + +select * from p, q where p.a = q.a and p.a > 5 * 100000 - 3; + +set plan_cache_mode to force_generic_plan ; +prepare s as select * from p, q where p.a = q.a and p.a > $1; +explain (costs off) execute s(5 * 100000 - 3); + +-- support perudo const. +prepare s2 as select * from p, q where p.a = q.a and p.a > abs($1::integer); +explain (costs off) execute s2(5 * 100000 - 3); + +-- test the IN Expr. +explain (costs off) select * from p, q where p.a = q.a and p.a in (30, 5000000 -3); + + -- 2.21.0