From a94f966c0f8b6e980036eb60ea90c39f1fb1e300 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Mon, 27 Jul 2026 15:27:39 +0200 Subject: [PATCH v10 14/21] Add basic regression tests for filter pushdown Adds three test suites specifically for Bloom filter pushdown, for basic schemas - two relations, starjoin and snowflake. The filter pushdown affects plans in a number of existing test suites, in an accidental way. These tests are focused on filter pushdown, generating plans with known plan. --- src/test/regress/expected/hashjoin_bloom.out | 65 +++ .../expected/hashjoin_bloom_snowflake.out | 182 -------- .../regress/expected/hashjoin_bloom_star.out | 410 ++++++++++++++++++ src/test/regress/parallel_schedule | 3 + src/test/regress/sql/hashjoin_bloom.sql | 43 ++ .../regress/sql/hashjoin_bloom_snowflake.sql | 142 ++++++ src/test/regress/sql/hashjoin_bloom_star.sql | 150 +++++++ 7 files changed, 813 insertions(+), 182 deletions(-) create mode 100644 src/test/regress/expected/hashjoin_bloom.out create mode 100644 src/test/regress/expected/hashjoin_bloom_star.out create mode 100644 src/test/regress/sql/hashjoin_bloom.sql create mode 100644 src/test/regress/sql/hashjoin_bloom_snowflake.sql create mode 100644 src/test/regress/sql/hashjoin_bloom_star.sql diff --git a/src/test/regress/expected/hashjoin_bloom.out b/src/test/regress/expected/hashjoin_bloom.out new file mode 100644 index 00000000000..aa967d76063 --- /dev/null +++ b/src/test/regress/expected/hashjoin_bloom.out @@ -0,0 +1,65 @@ +-- tests to validate bloom filter pushdown +-- no parallel query support for now +SET max_parallel_workers_per_gather = 0; +-- stabilize estimates +SET default_statistics_target = 10000; +-- a couple very simple join queries +CREATE TABLE bloom_simple_dim (id int, r real); +CREATE TABLE bloom_simple_fact (id int, padding text); +INSERT INTO bloom_simple_dim SELECT i, random() FROM generate_series(1,1000) s(i); +INSERT INTO bloom_simple_fact +SELECT + 1 + mod(i, 1000), + md5(i::text) +FROM generate_series(1,100000) s(i); +VACUUM ANALYZE; +-- simple query, no join is selective enough for a filter +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_simple_fact f +JOIN bloom_simple_dim d ON (f.id = d.id); + QUERY PLAN +-------------------------------------------- + Hash Join + Hash Cond: (f.id = d.id) + -> Seq Scan on bloom_simple_fact f + -> Hash + -> Seq Scan on bloom_simple_dim d +(5 rows) + +-- join is 75% selective (not enough for a filter to be created) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_simple_fact f +JOIN bloom_simple_dim d ON (f.id = d.id) +WHERE d.r < 0.75; + QUERY PLAN +------------------------------------------------------ + Hash Join + Hash Cond: (f.id = d.id) + -> Seq Scan on bloom_simple_fact f + -> Hash + -> Seq Scan on bloom_simple_dim d + Filter: (r < '0.75'::double precision) +(6 rows) + +-- join is 50% selective (enough for a filter to be pushed down) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_simple_fact f +JOIN bloom_simple_dim d ON (f.id = d.id) +WHERE d.r < 0.5; + QUERY PLAN +----------------------------------------------------- + Hash Join + Hash Cond: (f.id = d.id) + -> Seq Scan on bloom_simple_fact f + Bloom Filter 1: keys=(id) + -> Hash + Bloom Filter 1 + -> Seq Scan on bloom_simple_dim d + Filter: (r < '0.5'::double precision) +(8 rows) + +DROP TABLE bloom_simple_dim; +DROP TABLE bloom_simple_fact; diff --git a/src/test/regress/expected/hashjoin_bloom_snowflake.out b/src/test/regress/expected/hashjoin_bloom_snowflake.out index d953b247cd2..21449cfe7b0 100644 --- a/src/test/regress/expected/hashjoin_bloom_snowflake.out +++ b/src/test/regress/expected/hashjoin_bloom_snowflake.out @@ -374,185 +374,3 @@ DROP TABLE bloom_snowflake_dim_2_1; DROP TABLE bloom_snowflake_dim_2_2; DROP TABLE bloom_snowflake_dim_2; DROP TABLE bloom_snowflake_fact; --- snowflake queries on multi-column FK joins -CREATE TABLE bloom_snowflake_multi_dim_1_1 (a int, b int, r real, primary key (a, b)); -CREATE TABLE bloom_snowflake_multi_dim_1_2 (a int, b int, r real, primary key (a, b)); -CREATE TABLE bloom_snowflake_multi_dim_1 ( - a int, b int, - id11a int, id11b int, - id12a int, id12b int, - r real, - foreign key (id11a, id11b) references bloom_snowflake_multi_dim_1_1(a, b), - foreign key (id12a, id12b) references bloom_snowflake_multi_dim_1_2(a, b), - primary key (a, b)); -CREATE TABLE bloom_snowflake_multi_dim_2_1 (a int, b int, r real, primary key (a, b)); -CREATE TABLE bloom_snowflake_multi_dim_2_2 (a int, b int, r real, primary key (a, b)); -CREATE TABLE bloom_snowflake_multi_dim_2 ( - a int, b int, - id21a int, id21b int, - id22a int, id22b int, - r real, - foreign key (id21a, id21b) references bloom_snowflake_multi_dim_2_1(a, b), - foreign key (id22a, id22b) references bloom_snowflake_multi_dim_2_2(a, b), - primary key (a, b)); -CREATE TABLE bloom_snowflake_multi_fact ( - id1a int, id1b int, - id2a int, id2b int, - padding text, - foreign key (id1a, id1b) references bloom_snowflake_multi_dim_1(a, b), - foreign key (id2a, id2b) references bloom_snowflake_multi_dim_2(a, b)); -SELECT setseed(0.5); - setseed ---------- - -(1 row) - -INSERT INTO bloom_snowflake_multi_dim_1_1 SELECT i, i, random() FROM generate_series(1, 1000) s(i); -INSERT INTO bloom_snowflake_multi_dim_1_2 SELECT i, i, random() FROM generate_series(1, 1000) s(i); -WITH d AS (SELECT i, 1 + mod((100000 * random())::int, 1000) AS a, 1 + mod((100000 * random())::int, 1000) AS b FROM generate_series(1, 1000) s(i)) -INSERT INTO bloom_snowflake_multi_dim_1 SELECT i, i, a, a, b, b, random() FROM d; -INSERT INTO bloom_snowflake_multi_dim_2_1 SELECT i, i, random() FROM generate_series(1, 10000) s(i); -INSERT INTO bloom_snowflake_multi_dim_2_2 SELECT i, i, random() FROM generate_series(1, 10000) s(i); -WITH d AS (SELECT i, 1 + mod((100000 * random())::int, 1000) AS a, 1 + mod((100000 * random())::int, 1000) AS b FROM generate_series(1, 1000) s(i)) -INSERT INTO bloom_snowflake_multi_dim_2 SELECT i, i, a, a, b, b, random() FROM d; -WITH d AS (SELECT 1 + mod((100000 * random())::int, 1000) AS a, 1 + mod((100000 * random())::int, 1000) AS b, md5(i::text) AS p FROM generate_series(1, 100000) AS s(i)) -INSERT INTO bloom_snowflake_multi_fact -SELECT - a, a, b, b, p -FROM d; -VACUUM ANALYZE; --- increase the accepted build size (includes the fact) -SET bloom_filter_pushdown_max_build_relids = 4; -EXPLAIN (ANALYZE, TIMING OFF, SUMMARY OFF, BUFFERS OFF) -SELECT * -FROM bloom_snowflake_multi_fact f -JOIN bloom_snowflake_multi_dim_1 d1 ON (f.id1a = d1.a AND f.id1b = d1.b) -JOIN bloom_snowflake_multi_dim_1_1 d11 ON (d1.id11a = d11.a AND d1.id11b = d11.b) -JOIN bloom_snowflake_multi_dim_1_2 d12 ON (d1.id12a = d12.a AND d1.id12b = d12.b) -WHERE d11.r < 0.45 AND d12.r < 0.55; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------- - Hash Join (cost=78.07..2418.84 rows=24628 width=101) (actual rows=23530.00 loops=1) - Hash Cond: ((f.id1a = d1.a) AND (f.id1b = d1.b)) - -> Seq Scan on bloom_snowflake_multi_fact f (cost=0.00..2156.00 rows=24628 width=49) (actual rows=23531.00 loops=1) - Bloom Filter 3: keys=(id1a, id1b) expected=24.6% checked=99999 rejected=76469 (76.5%) - -> Hash (cost=74.38..74.38 rows=246 width=52) (actual rows=234.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 28kB - Bloom Filter 3: bits=8192 hashes=4 memory=1kB checked=99999 rejected=76469 - -> Hash Join (cost=52.00..74.38 rows=246 width=52) (actual rows=234.00 loops=1) - Hash Cond: ((d1.id12a = d12.a) AND (d1.id12b = d12.b)) - -> Hash Join (cost=25.09..46.18 rows=246 width=40) (actual rows=235.00 loops=1) - Hash Cond: ((d1.id11a = d11.a) AND (d1.id11b = d11.b)) - -> Seq Scan on bloom_snowflake_multi_dim_1 d1 (cost=0.00..19.80 rows=246 width=28) (actual rows=236.00 loops=1) - Bloom Filter 1: keys=(id11a, id11b) expected=43.9% checked=996 rejected=569 (57.1%) - Bloom Filter 2: keys=(id12a, id12b) expected=56.1% checked=431 rejected=195 (45.2%) - -> Hash (cost=18.50..18.50 rows=439 width=12) (actual rows=440.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 27kB - Bloom Filter 1: bits=8192 hashes=4 memory=1kB checked=996 rejected=569 - -> Seq Scan on bloom_snowflake_multi_dim_1_1 d11 (cost=0.00..18.50 rows=439 width=12) (actual rows=440.00 loops=1) - Filter: (r < '0.45'::double precision) - Rows Removed by Filter: 560 - -> Hash (cost=18.50..18.50 rows=561 width=12) (actual rows=562.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 33kB - Bloom Filter 2: bits=8192 hashes=4 memory=1kB checked=431 rejected=195 - -> Seq Scan on bloom_snowflake_multi_dim_1_2 d12 (cost=0.00..18.50 rows=561 width=12) (actual rows=562.00 loops=1) - Filter: (r < '0.55'::double precision) - Rows Removed by Filter: 438 -(26 rows) - -EXPLAIN (ANALYZE, TIMING OFF, SUMMARY OFF, BUFFERS OFF) -SELECT * -FROM bloom_snowflake_multi_fact f -JOIN bloom_snowflake_multi_dim_1 d1 ON (f.id1a = d1.a AND f.id1b = d1.b) -JOIN bloom_snowflake_multi_dim_1_1 d11 ON (d1.id11a = d11.a AND d1.id11b = d11.b) -JOIN bloom_snowflake_multi_dim_1_2 d12 ON (d1.id12a = d12.a AND d1.id12b = d12.b) -WHERE d11.r < 0.75 AND d12.r < 0.75; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------- - Hash Join (cost=94.81..2667.85 rows=55564 width=101) (actual rows=55598.00 loops=1) - Hash Cond: ((f.id1a = d1.a) AND (f.id1b = d1.b)) - -> Seq Scan on bloom_snowflake_multi_fact f (cost=0.00..2156.00 rows=55564 width=49) (actual rows=55694.00 loops=1) - Bloom Filter 1: keys=(id1a, id1b) expected=55.6% checked=99999 rejected=44306 (44.3%) - -> Hash (cost=86.47..86.47 rows=556 width=52) (actual rows=555.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 54kB - Bloom Filter 1: bits=8192 hashes=4 memory=1kB checked=99999 rejected=44306 - -> Hash Join (cost=59.36..86.47 rows=556 width=52) (actual rows=555.00 loops=1) - Hash Cond: ((d1.id12a = d12.a) AND (d1.id12b = d12.b)) - -> Hash Join (cost=29.51..52.76 rows=734 width=40) (actual rows=737.00 loops=1) - Hash Cond: ((d1.id11a = d11.a) AND (d1.id11b = d11.b)) - -> Seq Scan on bloom_snowflake_multi_dim_1 d1 (cost=0.00..18.00 rows=1000 width=28) (actual rows=1000.00 loops=1) - -> Hash (cost=18.50..18.50 rows=734 width=12) (actual rows=735.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 40kB - -> Seq Scan on bloom_snowflake_multi_dim_1_1 d11 (cost=0.00..18.50 rows=734 width=12) (actual rows=735.00 loops=1) - Filter: (r < '0.75'::double precision) - Rows Removed by Filter: 265 - -> Hash (cost=18.50..18.50 rows=757 width=12) (actual rows=758.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 41kB - -> Seq Scan on bloom_snowflake_multi_dim_1_2 d12 (cost=0.00..18.50 rows=757 width=12) (actual rows=758.00 loops=1) - Filter: (r < '0.75'::double precision) - Rows Removed by Filter: 242 -(22 rows) - -EXPLAIN (ANALYZE, TIMING OFF, SUMMARY OFF, BUFFERS OFF) -SELECT * -FROM bloom_snowflake_multi_fact f -JOIN bloom_snowflake_multi_dim_1 d1 ON (f.id1a = d1.a AND f.id1b = d1.b) -JOIN bloom_snowflake_multi_dim_1_1 d11 ON (d1.id11a = d11.a AND d1.id11b = d11.b) -JOIN bloom_snowflake_multi_dim_1_2 d12 ON (d1.id12a = d12.a AND d1.id12b = d12.b) -JOIN bloom_snowflake_multi_dim_2 d2 ON (f.id2a = d2.a AND f.id2b = d2.b) -JOIN bloom_snowflake_multi_dim_2_1 d21 ON (d2.id21a = d21.a AND d2.id21b = d21.b) -JOIN bloom_snowflake_multi_dim_2_2 d22 ON (d2.id22a = d22.a AND d2.id22b = d22.b) -WHERE d11.r < 0.75 AND d12.r < 0.75; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Hash Join (cost=331.90..3322.23 rows=55564 width=153) (actual rows=55598.00 loops=1) - Hash Cond: ((f.id1a = d1.a) AND (f.id1b = d1.b)) - -> Hash Join (cost=237.09..2810.38 rows=55564 width=101) (actual rows=55694.00 loops=1) - Hash Cond: ((f.id2a = d2.a) AND (f.id2b = d2.b)) - -> Seq Scan on bloom_snowflake_multi_fact f (cost=0.00..2156.00 rows=55564 width=49) (actual rows=55694.00 loops=1) - Bloom Filter 1: keys=(id1a, id1b) expected=55.6% checked=100000 rejected=44306 (44.3%) - -> Hash (cost=222.09..222.09 rows=1000 width=52) (actual rows=1000.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 91kB - -> Merge Join (cost=170.14..222.09 rows=1000 width=52) (actual rows=1000.00 loops=1) - Merge Cond: ((d22.a = d2.id22a) AND (d22.b = d2.id22b)) - -> Index Scan using bloom_snowflake_multi_dim_2_2_pkey on bloom_snowflake_multi_dim_2_2 d22 (cost=0.29..395.16 rows=10000 width=12) (actual rows=1001.00 loops=1) - Index Searches: 1 - -> Sort (cost=169.85..172.35 rows=1000 width=40) (actual rows=1000.00 loops=1) - Sort Key: d2.id22a, d2.id22b - Sort Method: quicksort Memory: 79kB - -> Merge Join (cost=68.11..120.02 rows=1000 width=40) (actual rows=1000.00 loops=1) - Merge Cond: ((d21.a = d2.id21a) AND (d21.b = d2.id21b)) - -> Index Scan using bloom_snowflake_multi_dim_2_1_pkey on bloom_snowflake_multi_dim_2_1 d21 (cost=0.29..395.16 rows=10000 width=12) (actual rows=1000.00 loops=1) - Index Searches: 1 - -> Sort (cost=67.83..70.33 rows=1000 width=28) (actual rows=1000.00 loops=1) - Sort Key: d2.id21a, d2.id21b - Sort Method: quicksort Memory: 71kB - -> Seq Scan on bloom_snowflake_multi_dim_2 d2 (cost=0.00..18.00 rows=1000 width=28) (actual rows=1000.00 loops=1) - -> Hash (cost=86.47..86.47 rows=556 width=52) (actual rows=555.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 54kB - Bloom Filter 1: bits=8192 hashes=4 memory=1kB checked=100000 rejected=44306 - -> Hash Join (cost=59.36..86.47 rows=556 width=52) (actual rows=555.00 loops=1) - Hash Cond: ((d1.id12a = d12.a) AND (d1.id12b = d12.b)) - -> Hash Join (cost=29.51..52.76 rows=734 width=40) (actual rows=737.00 loops=1) - Hash Cond: ((d1.id11a = d11.a) AND (d1.id11b = d11.b)) - -> Seq Scan on bloom_snowflake_multi_dim_1 d1 (cost=0.00..18.00 rows=1000 width=28) (actual rows=1000.00 loops=1) - -> Hash (cost=18.50..18.50 rows=734 width=12) (actual rows=735.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 40kB - -> Seq Scan on bloom_snowflake_multi_dim_1_1 d11 (cost=0.00..18.50 rows=734 width=12) (actual rows=735.00 loops=1) - Filter: (r < '0.75'::double precision) - Rows Removed by Filter: 265 - -> Hash (cost=18.50..18.50 rows=757 width=12) (actual rows=758.00 loops=1) - Buckets: 1024 Batches: 1 Memory Usage: 41kB - -> Seq Scan on bloom_snowflake_multi_dim_1_2 d12 (cost=0.00..18.50 rows=757 width=12) (actual rows=758.00 loops=1) - Filter: (r < '0.75'::double precision) - Rows Removed by Filter: 242 -(41 rows) - -RESET bloom_filter_pushdown_max_build_relids; -DROP TABLE bloom_snowflake_multi_fact; -DROP TABLE bloom_snowflake_multi_dim_1; -DROP TABLE bloom_snowflake_multi_dim_2; -DROP TABLE bloom_snowflake_multi_dim_1_1; -DROP TABLE bloom_snowflake_multi_dim_1_2; -DROP TABLE bloom_snowflake_multi_dim_2_1; -DROP TABLE bloom_snowflake_multi_dim_2_2; diff --git a/src/test/regress/expected/hashjoin_bloom_star.out b/src/test/regress/expected/hashjoin_bloom_star.out new file mode 100644 index 00000000000..ca053673bd9 --- /dev/null +++ b/src/test/regress/expected/hashjoin_bloom_star.out @@ -0,0 +1,410 @@ +-- tests to validate bloom filter pushdown +-- no parallel query support for now +SET max_parallel_workers_per_gather = 0; +-- stabilize estimates +SET default_statistics_target = 10000; +-- needed, because the filter pushdown eliminates one of the inputs for +-- choosing join order (reduction of result size) +SET join_collapse_limit = 1; +-- simple starjoin queries (fact + up to 7 dimensions) +CREATE TABLE bloom_star_dim_1 (id int, r real); +CREATE TABLE bloom_star_dim_2 (id int, r real); +CREATE TABLE bloom_star_dim_3 (id int, r real); +CREATE TABLE bloom_star_dim_4 (id int, r real); +CREATE TABLE bloom_star_dim_5 (id int, r real); +CREATE TABLE bloom_star_dim_6 (id int, r real); +CREATE TABLE bloom_star_dim_7 (id int, r real); +CREATE TABLE bloom_star_fact (id1 int, id2 int, id3 int, id4 int, id5 int, id6 int, id7 int, padding text); +INSERT INTO bloom_star_dim_1 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_2 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_3 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_4 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_5 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_6 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_7 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_fact +SELECT + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + md5(i::text) +FROM generate_series(1,1000000) s(i); +VACUUM ANALYZE; +-- simple query, no join is selective enough for a filter +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id); + QUERY PLAN +--------------------------------------------------------------------------------- + Hash Join + Hash Cond: (f.id7 = d7.id) + -> Hash Join + Hash Cond: (f.id6 = d6.id) + -> Hash Join + Hash Cond: (f.id5 = d5.id) + -> Hash Join + Hash Cond: (f.id4 = d4.id) + -> Hash Join + Hash Cond: (f.id3 = d3.id) + -> Hash Join + Hash Cond: (f.id2 = d2.id) + -> Hash Join + Hash Cond: (f.id1 = d1.id) + -> Seq Scan on bloom_star_fact f + -> Hash + -> Seq Scan on bloom_star_dim_1 d1 + -> Hash + -> Seq Scan on bloom_star_dim_2 d2 + -> Hash + -> Seq Scan on bloom_star_dim_3 d3 + -> Hash + -> Seq Scan on bloom_star_dim_4 d4 + -> Hash + -> Seq Scan on bloom_star_dim_5 d5 + -> Hash + -> Seq Scan on bloom_star_dim_6 d6 + -> Hash + -> Seq Scan on bloom_star_dim_7 d7 +(29 rows) + +-- last join is 75% selective (not enough for a filter to be created) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d7.r < 0.75; + QUERY PLAN +--------------------------------------------------------------------------------- + Hash Join + Hash Cond: (f.id7 = d7.id) + -> Hash Join + Hash Cond: (f.id6 = d6.id) + -> Hash Join + Hash Cond: (f.id5 = d5.id) + -> Hash Join + Hash Cond: (f.id4 = d4.id) + -> Hash Join + Hash Cond: (f.id3 = d3.id) + -> Hash Join + Hash Cond: (f.id2 = d2.id) + -> Hash Join + Hash Cond: (f.id1 = d1.id) + -> Seq Scan on bloom_star_fact f + -> Hash + -> Seq Scan on bloom_star_dim_1 d1 + -> Hash + -> Seq Scan on bloom_star_dim_2 d2 + -> Hash + -> Seq Scan on bloom_star_dim_3 d3 + -> Hash + -> Seq Scan on bloom_star_dim_4 d4 + -> Hash + -> Seq Scan on bloom_star_dim_5 d5 + -> Hash + -> Seq Scan on bloom_star_dim_6 d6 + -> Hash + -> Seq Scan on bloom_star_dim_7 d7 + Filter: (r < '0.75'::double precision) +(30 rows) + +-- last join is 50% selective (good enough for a filter push down) +-- the join will be executed done last +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d7.r < 0.5; + QUERY PLAN +--------------------------------------------------------------------------------- + Hash Join + Hash Cond: (f.id7 = d7.id) + -> Hash Join + Hash Cond: (f.id6 = d6.id) + -> Hash Join + Hash Cond: (f.id5 = d5.id) + -> Hash Join + Hash Cond: (f.id4 = d4.id) + -> Hash Join + Hash Cond: (f.id3 = d3.id) + -> Hash Join + Hash Cond: (f.id2 = d2.id) + -> Hash Join + Hash Cond: (f.id1 = d1.id) + -> Seq Scan on bloom_star_fact f + Bloom Filter 1: keys=(id7) + -> Hash + -> Seq Scan on bloom_star_dim_1 d1 + -> Hash + -> Seq Scan on bloom_star_dim_2 d2 + -> Hash + -> Seq Scan on bloom_star_dim_3 d3 + -> Hash + -> Seq Scan on bloom_star_dim_4 d4 + -> Hash + -> Seq Scan on bloom_star_dim_5 d5 + -> Hash + -> Seq Scan on bloom_star_dim_6 d6 + -> Hash + Bloom Filter 1 + -> Seq Scan on bloom_star_dim_7 d7 + Filter: (r < '0.5'::double precision) +(32 rows) + +-- first join is 50% selective (good enough for a filter push down) +-- the join will be executed done last +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.5; + QUERY PLAN +----------------------------------------------------------------------------------------- + Hash Join + Hash Cond: (f.id7 = d7.id) + -> Hash Join + Hash Cond: (f.id6 = d6.id) + -> Hash Join + Hash Cond: (f.id5 = d5.id) + -> Hash Join + Hash Cond: (f.id4 = d4.id) + -> Hash Join + Hash Cond: (f.id3 = d3.id) + -> Hash Join + Hash Cond: (f.id2 = d2.id) + -> Hash Join + Hash Cond: (f.id1 = d1.id) + -> Seq Scan on bloom_star_fact f + Bloom Filter 1: keys=(id1) + -> Hash + Bloom Filter 1 + -> Seq Scan on bloom_star_dim_1 d1 + Filter: (r < '0.5'::double precision) + -> Hash + -> Seq Scan on bloom_star_dim_2 d2 + -> Hash + -> Seq Scan on bloom_star_dim_3 d3 + -> Hash + -> Seq Scan on bloom_star_dim_4 d4 + -> Hash + -> Seq Scan on bloom_star_dim_5 d5 + -> Hash + -> Seq Scan on bloom_star_dim_6 d6 + -> Hash + -> Seq Scan on bloom_star_dim_7 d7 +(32 rows) + +-- two joins 50% selective +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.4 AND d7.r < 0.5; + QUERY PLAN +----------------------------------------------------------------------------------------- + Hash Join + Hash Cond: (f.id7 = d7.id) + -> Hash Join + Hash Cond: (f.id6 = d6.id) + -> Hash Join + Hash Cond: (f.id5 = d5.id) + -> Hash Join + Hash Cond: (f.id4 = d4.id) + -> Hash Join + Hash Cond: (f.id3 = d3.id) + -> Hash Join + Hash Cond: (f.id2 = d2.id) + -> Hash Join + Hash Cond: (f.id1 = d1.id) + -> Seq Scan on bloom_star_fact f + Bloom Filter 1: keys=(id1) + Bloom Filter 2: keys=(id7) + -> Hash + Bloom Filter 1 + -> Seq Scan on bloom_star_dim_1 d1 + Filter: (r < '0.4'::double precision) + -> Hash + -> Seq Scan on bloom_star_dim_2 d2 + -> Hash + -> Seq Scan on bloom_star_dim_3 d3 + -> Hash + -> Seq Scan on bloom_star_dim_4 d4 + -> Hash + -> Seq Scan on bloom_star_dim_5 d5 + -> Hash + -> Seq Scan on bloom_star_dim_6 d6 + -> Hash + Bloom Filter 2 + -> Seq Scan on bloom_star_dim_7 d7 + Filter: (r < '0.5'::double precision) +(35 rows) + +-- all joins selective for a filter (more than how many we allow) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.3 AND d2.r < 0.35 AND d3.r < 0.4 AND d4.r < 0.45 AND d5.r < 0.5 AND d6.r < 0.55 AND d7.r < 0.6; + QUERY PLAN +----------------------------------------------------------------------------------------- + Hash Join + Hash Cond: (f.id7 = d7.id) + -> Hash Join + Hash Cond: (f.id6 = d6.id) + -> Hash Join + Hash Cond: (f.id5 = d5.id) + -> Hash Join + Hash Cond: (f.id4 = d4.id) + -> Hash Join + Hash Cond: (f.id3 = d3.id) + -> Hash Join + Hash Cond: (f.id2 = d2.id) + -> Hash Join + Hash Cond: (f.id1 = d1.id) + -> Seq Scan on bloom_star_fact f + Bloom Filter 1: keys=(id1) + Bloom Filter 2: keys=(id2) + Bloom Filter 3: keys=(id3) + -> Hash + Bloom Filter 1 + -> Seq Scan on bloom_star_dim_1 d1 + Filter: (r < '0.3'::double precision) + -> Hash + Bloom Filter 2 + -> Seq Scan on bloom_star_dim_2 d2 + Filter: (r < '0.35'::double precision) + -> Hash + Bloom Filter 3 + -> Seq Scan on bloom_star_dim_3 d3 + Filter: (r < '0.4'::double precision) + -> Hash + -> Seq Scan on bloom_star_dim_4 d4 + Filter: (r < '0.45'::double precision) + -> Hash + -> Seq Scan on bloom_star_dim_5 d5 + Filter: (r < '0.5'::double precision) + -> Hash + -> Seq Scan on bloom_star_dim_6 d6 + Filter: (r < '0.55'::double precision) + -> Hash + -> Seq Scan on bloom_star_dim_7 d7 + Filter: (r < '0.6'::double precision) +(42 rows) + +SET bloom_filter_pushdown_max = 10; +-- all joins selective for a filter +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.3 AND d2.r < 0.35 AND d3.r < 0.4 AND d4.r < 0.45 AND d5.r < 0.5 AND d6.r < 0.55 AND d7.r < 0.6; + QUERY PLAN +----------------------------------------------------------------------------------------- + Hash Join + Hash Cond: (f.id7 = d7.id) + -> Hash Join + Hash Cond: (f.id6 = d6.id) + -> Hash Join + Hash Cond: (f.id5 = d5.id) + -> Hash Join + Hash Cond: (f.id4 = d4.id) + -> Hash Join + Hash Cond: (f.id3 = d3.id) + -> Hash Join + Hash Cond: (f.id2 = d2.id) + -> Hash Join + Hash Cond: (f.id1 = d1.id) + -> Seq Scan on bloom_star_fact f + Bloom Filter 1: keys=(id1) + Bloom Filter 2: keys=(id2) + Bloom Filter 3: keys=(id3) + Bloom Filter 4: keys=(id4) + Bloom Filter 5: keys=(id5) + Bloom Filter 6: keys=(id6) + Bloom Filter 7: keys=(id7) + -> Hash + Bloom Filter 1 + -> Seq Scan on bloom_star_dim_1 d1 + Filter: (r < '0.3'::double precision) + -> Hash + Bloom Filter 2 + -> Seq Scan on bloom_star_dim_2 d2 + Filter: (r < '0.35'::double precision) + -> Hash + Bloom Filter 3 + -> Seq Scan on bloom_star_dim_3 d3 + Filter: (r < '0.4'::double precision) + -> Hash + Bloom Filter 4 + -> Seq Scan on bloom_star_dim_4 d4 + Filter: (r < '0.45'::double precision) + -> Hash + Bloom Filter 5 + -> Seq Scan on bloom_star_dim_5 d5 + Filter: (r < '0.5'::double precision) + -> Hash + Bloom Filter 6 + -> Seq Scan on bloom_star_dim_6 d6 + Filter: (r < '0.55'::double precision) + -> Hash + Bloom Filter 7 + -> Seq Scan on bloom_star_dim_7 d7 + Filter: (r < '0.6'::double precision) +(50 rows) + +RESET bloom_filter_pushdown_max; +RESET join_collapse_limit; +DROP TABLE bloom_star_dim_1; +DROP TABLE bloom_star_dim_2; +DROP TABLE bloom_star_dim_3; +DROP TABLE bloom_star_dim_4; +DROP TABLE bloom_star_dim_5; +DROP TABLE bloom_star_dim_6; +DROP TABLE bloom_star_dim_7; +DROP TABLE bloom_star_fact; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 8fa0a6c47fb..0de7bdc3c56 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -146,3 +146,6 @@ test: fast_default # run tablespace test at the end because it drops the tablespace created during # setup that other tests may use. test: tablespace + +# tests for hashjoin bloom filter pushdown +test: hashjoin_bloom hashjoin_bloom_star hashjoin_bloom_snowflake diff --git a/src/test/regress/sql/hashjoin_bloom.sql b/src/test/regress/sql/hashjoin_bloom.sql new file mode 100644 index 00000000000..47554daec4c --- /dev/null +++ b/src/test/regress/sql/hashjoin_bloom.sql @@ -0,0 +1,43 @@ +-- tests to validate bloom filter pushdown +-- no parallel query support for now +SET max_parallel_workers_per_gather = 0; + +-- stabilize estimates +SET default_statistics_target = 10000; + +-- a couple very simple join queries +CREATE TABLE bloom_simple_dim (id int, r real); +CREATE TABLE bloom_simple_fact (id int, padding text); + +INSERT INTO bloom_simple_dim SELECT i, random() FROM generate_series(1,1000) s(i); + +INSERT INTO bloom_simple_fact +SELECT + 1 + mod(i, 1000), + md5(i::text) +FROM generate_series(1,100000) s(i); + +VACUUM ANALYZE; + +-- simple query, no join is selective enough for a filter +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_simple_fact f +JOIN bloom_simple_dim d ON (f.id = d.id); + +-- join is 75% selective (not enough for a filter to be created) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_simple_fact f +JOIN bloom_simple_dim d ON (f.id = d.id) +WHERE d.r < 0.75; + +-- join is 50% selective (enough for a filter to be pushed down) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_simple_fact f +JOIN bloom_simple_dim d ON (f.id = d.id) +WHERE d.r < 0.5; + +DROP TABLE bloom_simple_dim; +DROP TABLE bloom_simple_fact; diff --git a/src/test/regress/sql/hashjoin_bloom_snowflake.sql b/src/test/regress/sql/hashjoin_bloom_snowflake.sql new file mode 100644 index 00000000000..9fda90bed9b --- /dev/null +++ b/src/test/regress/sql/hashjoin_bloom_snowflake.sql @@ -0,0 +1,142 @@ +-- tests to validate bloom filter pushdown +-- no parallel query support for now +SET max_parallel_workers_per_gather = 0; + +-- stabilize estimates +SET default_statistics_target = 10000; + +-- simple snowflake queries (fact + up to 7 dimensions) +CREATE TABLE bloom_snowflake_dim_1_1 (id int, r real); +CREATE TABLE bloom_snowflake_dim_1_2 (id int, r real); +CREATE TABLE bloom_snowflake_dim_1 (id int, id11 int, id12 int, r real); +CREATE TABLE bloom_snowflake_dim_2_1 (id int, r real); +CREATE TABLE bloom_snowflake_dim_2_2 (id int, r real); +CREATE TABLE bloom_snowflake_dim_2 (id int, id21 int, id22 int, r real); + +CREATE TABLE bloom_snowflake_fact (id1 int, id2 int, padding text); + +INSERT INTO bloom_snowflake_dim_1_1 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_snowflake_dim_1_2 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_snowflake_dim_1 SELECT i, 1 + mod(i, 10000), 1 + mod(i, 10000), random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_snowflake_dim_2_1 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_snowflake_dim_2_2 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_snowflake_dim_2 SELECT i, 1 + mod(i, 10000), 1 + mod(i, 10000), random() FROM generate_series(1,10000) s(i); + +INSERT INTO bloom_snowflake_fact +SELECT + 1 + mod(i, 10000), + 1 + mod(i, 10000), + md5(i::text) +FROM generate_series(1,1000000) s(i); + +VACUUM ANALYZE; + +-- simple query, no join is selective enough for a filter +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id); + +-- join is 75% selective (not enough for a filter to be created) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id) +WHERE d1.r < 0.75; + +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id) +WHERE d11.r < 0.75; + +-- join is 50% selective (good enough for pushdown) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id) +WHERE d1.r < 0.5; + +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id) +WHERE d11.r < 0.5; + +-- increase the accepted build size (includes the fact) +SET bloom_filter_pushdown_max_build_relids = 4; + +-- join is 50% selective (good enough for pushdown) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id) +WHERE d1.r < 0.5; + +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id) +WHERE d11.r < 0.5; + +-- needed to stabilize the join order +SET join_collapse_limit = 1; + +-- two joins with 75% selectivity (not enough for pushdown individually, +-- but good enough when combined) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_snowflake_fact f +JOIN bloom_snowflake_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_snowflake_dim_1_1 d11 ON (d1.id11 = d11.id) +JOIN bloom_snowflake_dim_1_2 d12 ON (d1.id12 = d12.id) +JOIN bloom_snowflake_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_snowflake_dim_2_1 d21 ON (d2.id21 = d21.id) +JOIN bloom_snowflake_dim_2_2 d22 ON (d2.id22 = d22.id) +WHERE d11.r < 0.75 AND d12.r < 0.75; + +RESET join_collapse_limit; +RESET bloom_filter_pushdown_max_build_relids; + +DROP TABLE bloom_snowflake_dim_1_1; +DROP TABLE bloom_snowflake_dim_1_2; +DROP TABLE bloom_snowflake_dim_1; +DROP TABLE bloom_snowflake_dim_2_1; +DROP TABLE bloom_snowflake_dim_2_2; +DROP TABLE bloom_snowflake_dim_2; +DROP TABLE bloom_snowflake_fact; diff --git a/src/test/regress/sql/hashjoin_bloom_star.sql b/src/test/regress/sql/hashjoin_bloom_star.sql new file mode 100644 index 00000000000..8af3513ba7a --- /dev/null +++ b/src/test/regress/sql/hashjoin_bloom_star.sql @@ -0,0 +1,150 @@ +-- tests to validate bloom filter pushdown +-- no parallel query support for now +SET max_parallel_workers_per_gather = 0; + +-- stabilize estimates +SET default_statistics_target = 10000; + +-- needed, because the filter pushdown eliminates one of the inputs for +-- choosing join order (reduction of result size) +SET join_collapse_limit = 1; + +-- simple starjoin queries (fact + up to 7 dimensions) +CREATE TABLE bloom_star_dim_1 (id int, r real); +CREATE TABLE bloom_star_dim_2 (id int, r real); +CREATE TABLE bloom_star_dim_3 (id int, r real); +CREATE TABLE bloom_star_dim_4 (id int, r real); +CREATE TABLE bloom_star_dim_5 (id int, r real); +CREATE TABLE bloom_star_dim_6 (id int, r real); +CREATE TABLE bloom_star_dim_7 (id int, r real); + +CREATE TABLE bloom_star_fact (id1 int, id2 int, id3 int, id4 int, id5 int, id6 int, id7 int, padding text); + +INSERT INTO bloom_star_dim_1 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_2 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_3 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_4 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_5 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_6 SELECT i, random() FROM generate_series(1,10000) s(i); +INSERT INTO bloom_star_dim_7 SELECT i, random() FROM generate_series(1,10000) s(i); + +INSERT INTO bloom_star_fact +SELECT + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + 1 + mod(i, 10000), + md5(i::text) +FROM generate_series(1,1000000) s(i); + +VACUUM ANALYZE; + +-- simple query, no join is selective enough for a filter +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id); + +-- last join is 75% selective (not enough for a filter to be created) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d7.r < 0.75; + +-- last join is 50% selective (good enough for a filter push down) +-- the join will be executed done last +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d7.r < 0.5; + +-- first join is 50% selective (good enough for a filter push down) +-- the join will be executed done last +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.5; + +-- two joins 50% selective +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.4 AND d7.r < 0.5; + +-- all joins selective for a filter (more than how many we allow) +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.3 AND d2.r < 0.35 AND d3.r < 0.4 AND d4.r < 0.45 AND d5.r < 0.5 AND d6.r < 0.55 AND d7.r < 0.6; + + +SET bloom_filter_pushdown_max = 10; + +-- all joins selective for a filter +EXPLAIN (COSTS OFF) +SELECT * +FROM bloom_star_fact f +JOIN bloom_star_dim_1 d1 ON (f.id1 = d1.id) +JOIN bloom_star_dim_2 d2 ON (f.id2 = d2.id) +JOIN bloom_star_dim_3 d3 ON (f.id3 = d3.id) +JOIN bloom_star_dim_4 d4 ON (f.id4 = d4.id) +JOIN bloom_star_dim_5 d5 ON (f.id5 = d5.id) +JOIN bloom_star_dim_6 d6 ON (f.id6 = d6.id) +JOIN bloom_star_dim_7 d7 ON (f.id7 = d7.id) +WHERE d1.r < 0.3 AND d2.r < 0.35 AND d3.r < 0.4 AND d4.r < 0.45 AND d5.r < 0.5 AND d6.r < 0.55 AND d7.r < 0.6; + +RESET bloom_filter_pushdown_max; +RESET join_collapse_limit; + +DROP TABLE bloom_star_dim_1; +DROP TABLE bloom_star_dim_2; +DROP TABLE bloom_star_dim_3; +DROP TABLE bloom_star_dim_4; +DROP TABLE bloom_star_dim_5; +DROP TABLE bloom_star_dim_6; +DROP TABLE bloom_star_dim_7; +DROP TABLE bloom_star_fact; -- 2.50.1 (Apple Git-155)