diff options
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/regress/expected/aggregates.out | 2 | ||||
| -rw-r--r-- | src/test/regress/expected/join.out | 131 | ||||
| -rw-r--r-- | src/test/regress/expected/partition_prune.out | 5 | ||||
| -rw-r--r-- | src/test/regress/expected/resultcache.out | 158 | ||||
| -rw-r--r-- | src/test/regress/expected/subselect.out | 20 | ||||
| -rw-r--r-- | src/test/regress/expected/sysviews.out | 3 | ||||
| -rw-r--r-- | src/test/regress/parallel_schedule | 2 | ||||
| -rw-r--r-- | src/test/regress/serial_schedule | 1 | ||||
| -rw-r--r-- | src/test/regress/sql/aggregates.sql | 2 | ||||
| -rw-r--r-- | src/test/regress/sql/join.sql | 2 | ||||
| -rw-r--r-- | src/test/regress/sql/partition_prune.sql | 5 | ||||
| -rw-r--r-- | src/test/regress/sql/resultcache.sql | 91 |
12 files changed, 358 insertions, 64 deletions
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 1ae0e5d9398..ca06d41dd04 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -2584,6 +2584,7 @@ select v||'a', case when v||'a' = 'aa' then 1 else 0 end, count(*) -- Make sure that generation of HashAggregate for uniqification purposes -- does not lead to array overflow due to unexpected duplicate hash keys -- see CAFeeJoKKu0u+A_A9R9316djW-YW3-+Gtgvy3ju655qRHR3jtdA@mail.gmail.com +set enable_resultcache to off; explain (costs off) select 1 from tenk1 where (hundred, thousand) in (select twothousand, twothousand from onek); @@ -2599,6 +2600,7 @@ explain (costs off) -> Seq Scan on onek (8 rows) +reset enable_resultcache; -- -- Hash Aggregation Spill tests -- diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 04e802d4213..86fd3907c53 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -2536,6 +2536,7 @@ reset enable_nestloop; -- set work_mem to '64kB'; set enable_mergejoin to off; +set enable_resultcache to off; explain (costs off) select count(*) from tenk1 a, tenk1 b where a.hundred = b.thousand and (b.fivethous % 10) < 10; @@ -2559,6 +2560,7 @@ select count(*) from tenk1 a, tenk1 b reset work_mem; reset enable_mergejoin; +reset enable_resultcache; -- -- regression test for 8.2 bug with improper re-ordering of left joins -- @@ -3663,8 +3665,8 @@ select * from tenk1 t1 left join (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2) on t1.hundred = t2.hundred and t1.ten = t3.ten where t1.unique1 = 1; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------- Nested Loop Left Join -> Index Scan using tenk1_unique1 on tenk1 t1 Index Cond: (unique1 = 1) @@ -3674,17 +3676,19 @@ where t1.unique1 = 1; Recheck Cond: (t1.hundred = hundred) -> Bitmap Index Scan on tenk1_hundred Index Cond: (hundred = t1.hundred) - -> Index Scan using tenk1_unique2 on tenk1 t3 - Index Cond: (unique2 = t2.thousand) -(11 rows) + -> Result Cache + Cache Key: t2.thousand + -> Index Scan using tenk1_unique2 on tenk1 t3 + Index Cond: (unique2 = t2.thousand) +(13 rows) explain (costs off) select * from tenk1 t1 left join (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2) on t1.hundred = t2.hundred and t1.ten + t2.ten = t3.ten where t1.unique1 = 1; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------- Nested Loop Left Join -> Index Scan using tenk1_unique1 on tenk1 t1 Index Cond: (unique1 = 1) @@ -3694,9 +3698,11 @@ where t1.unique1 = 1; Recheck Cond: (t1.hundred = hundred) -> Bitmap Index Scan on tenk1_hundred Index Cond: (hundred = t1.hundred) - -> Index Scan using tenk1_unique2 on tenk1 t3 - Index Cond: (unique2 = t2.thousand) -(11 rows) + -> Result Cache + Cache Key: t2.thousand + -> Index Scan using tenk1_unique2 on tenk1 t3 + Index Cond: (unique2 = t2.thousand) +(13 rows) explain (costs off) select count(*) from @@ -4210,8 +4216,8 @@ where t1.f1 = ss.f1; QUERY PLAN -------------------------------------------------- Nested Loop - Output: t1.f1, i8.q1, i8.q2, (i8.q1), t2.f1 - Join Filter: (t1.f1 = t2.f1) + Output: t1.f1, i8.q1, i8.q2, q1, f1 + Join Filter: (t1.f1 = f1) -> Nested Loop Left Join Output: t1.f1, i8.q1, i8.q2 -> Seq Scan on public.text_tbl t1 @@ -4221,11 +4227,14 @@ where t1.f1 = ss.f1; -> Seq Scan on public.int8_tbl i8 Output: i8.q1, i8.q2 Filter: (i8.q2 = 123) - -> Limit - Output: (i8.q1), t2.f1 - -> Seq Scan on public.text_tbl t2 - Output: i8.q1, t2.f1 -(16 rows) + -> Result Cache + Output: q1, f1 + Cache Key: i8.q1 + -> Limit + Output: (i8.q1), t2.f1 + -> Seq Scan on public.text_tbl t2 + Output: i8.q1, t2.f1 +(19 rows) select * from text_tbl t1 @@ -4246,13 +4255,13 @@ select * from lateral (select i8.q1, t2.f1 from text_tbl t2 limit 1) as ss1, lateral (select ss1.* from text_tbl t3 limit 1) as ss2 where t1.f1 = ss2.f1; - QUERY PLAN -------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------- Nested Loop - Output: t1.f1, i8.q1, i8.q2, (i8.q1), t2.f1, ((i8.q1)), (t2.f1) - Join Filter: (t1.f1 = (t2.f1)) + Output: t1.f1, i8.q1, i8.q2, q1, f1, q1, f1 + Join Filter: (t1.f1 = f1) -> Nested Loop - Output: t1.f1, i8.q1, i8.q2, (i8.q1), t2.f1 + Output: t1.f1, i8.q1, i8.q2, q1, f1 -> Nested Loop Left Join Output: t1.f1, i8.q1, i8.q2 -> Seq Scan on public.text_tbl t1 @@ -4262,15 +4271,21 @@ where t1.f1 = ss2.f1; -> Seq Scan on public.int8_tbl i8 Output: i8.q1, i8.q2 Filter: (i8.q2 = 123) + -> Result Cache + Output: q1, f1 + Cache Key: i8.q1 + -> Limit + Output: (i8.q1), t2.f1 + -> Seq Scan on public.text_tbl t2 + Output: i8.q1, t2.f1 + -> Result Cache + Output: q1, f1 + Cache Key: q1, f1 -> Limit - Output: (i8.q1), t2.f1 - -> Seq Scan on public.text_tbl t2 - Output: i8.q1, t2.f1 - -> Limit - Output: ((i8.q1)), (t2.f1) - -> Seq Scan on public.text_tbl t3 - Output: (i8.q1), t2.f1 -(22 rows) + Output: (q1), (f1) + -> Seq Scan on public.text_tbl t3 + Output: q1, f1 +(28 rows) select * from text_tbl t1 @@ -4316,14 +4331,17 @@ where tt1.f1 = ss1.c0; -> Seq Scan on public.text_tbl tt4 Output: tt4.f1 Filter: (tt4.f1 = 'foo'::text) - -> Subquery Scan on ss1 + -> Result Cache Output: ss1.c0 - Filter: (ss1.c0 = 'foo'::text) - -> Limit - Output: (tt4.f1) - -> Seq Scan on public.text_tbl tt5 - Output: tt4.f1 -(29 rows) + Cache Key: tt4.f1 + -> Subquery Scan on ss1 + Output: ss1.c0 + Filter: (ss1.c0 = 'foo'::text) + -> Limit + Output: (tt4.f1) + -> Seq Scan on public.text_tbl tt5 + Output: tt4.f1 +(32 rows) select 1 from text_tbl as tt1 @@ -4997,34 +5015,40 @@ select count(*) from tenk1 a, lateral generate_series(1,two) g; explain (costs off) select count(*) from tenk1 a, lateral generate_series(1,two) g; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------ Aggregate -> Nested Loop -> Seq Scan on tenk1 a - -> Function Scan on generate_series g -(4 rows) + -> Result Cache + Cache Key: a.two + -> Function Scan on generate_series g +(6 rows) explain (costs off) select count(*) from tenk1 a cross join lateral generate_series(1,two) g; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------ Aggregate -> Nested Loop -> Seq Scan on tenk1 a - -> Function Scan on generate_series g -(4 rows) + -> Result Cache + Cache Key: a.two + -> Function Scan on generate_series g +(6 rows) -- don't need the explicit LATERAL keyword for functions explain (costs off) select count(*) from tenk1 a, generate_series(1,two) g; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------ Aggregate -> Nested Loop -> Seq Scan on tenk1 a - -> Function Scan on generate_series g -(4 rows) + -> Result Cache + Cache Key: a.two + -> Function Scan on generate_series g +(6 rows) -- lateral with UNION ALL subselect explain (costs off) @@ -5079,14 +5103,15 @@ explain (costs off) QUERY PLAN ------------------------------------------------------------------ Aggregate - -> Hash Join - Hash Cond: ("*VALUES*".column1 = b.unique2) + -> Nested Loop -> Nested Loop -> Index Only Scan using tenk1_unique1 on tenk1 a -> Values Scan on "*VALUES*" - -> Hash + -> Result Cache + Cache Key: "*VALUES*".column1 -> Index Only Scan using tenk1_unique2 on tenk1 b -(8 rows) + Index Cond: (unique2 = "*VALUES*".column1) +(9 rows) select count(*) from tenk1 a, tenk1 b join lateral (values(a.unique1),(-1)) ss(x) on b.unique2 = ss.x; diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index c4e827caec3..1a7149bfd57 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1958,6 +1958,9 @@ begin ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N'); ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N'); ln := regexp_replace(ln, 'Rows Removed by Filter: \d+', 'Rows Removed by Filter: N'); + ln := regexp_replace(ln, 'Hits: \d+', 'Hits: N'); + ln := regexp_replace(ln, 'Misses: \d+', 'Misses: N'); + ln := regexp_replace(ln, 'Memory Usage: \d+', 'Memory Usage: N'); return next ln; end loop; end; @@ -2085,6 +2088,7 @@ create index ab_a3_b2_a_idx on ab_a3_b2 (a); create index ab_a3_b3_a_idx on ab_a3_b3 (a); set enable_hashjoin = 0; set enable_mergejoin = 0; +set enable_resultcache = 0; select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(0, 0, 1)'); explain_parallel_append -------------------------------------------------------------------------------------------------------- @@ -2253,6 +2257,7 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on reset enable_hashjoin; reset enable_mergejoin; +reset enable_resultcache; reset parallel_setup_cost; reset parallel_tuple_cost; reset min_parallel_table_scan_size; diff --git a/src/test/regress/expected/resultcache.out b/src/test/regress/expected/resultcache.out new file mode 100644 index 00000000000..65d9e251692 --- /dev/null +++ b/src/test/regress/expected/resultcache.out @@ -0,0 +1,158 @@ +-- Perform tests on the Result Cache node. +-- The cache hits/misses/evictions from the Result Cache node can vary between +-- machines. Let's just replace the number with an 'N'. In order to allow us +-- to perform validation when the measure was zero, we replace a zero value +-- with "Zero". All other numbers are replaced with 'N'. +create function explain_resultcache(query text, hide_hitmiss bool) returns setof text +language plpgsql as +$$ +declare + ln text; +begin + for ln in + execute format('explain (analyze, costs off, summary off, timing off) %s', + query) + loop + if hide_hitmiss = true then + ln := regexp_replace(ln, 'Hits: 0', 'Hits: Zero'); + ln := regexp_replace(ln, 'Hits: \d+', 'Hits: N'); + ln := regexp_replace(ln, 'Misses: 0', 'Misses: Zero'); + ln := regexp_replace(ln, 'Misses: \d+', 'Misses: N'); + end if; + ln := regexp_replace(ln, 'Evictions: 0', 'Evictions: Zero'); + ln := regexp_replace(ln, 'Evictions: \d+', 'Evictions: N'); + ln := regexp_replace(ln, 'Memory Usage: \d+', 'Memory Usage: N'); + ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N'); + return next ln; + end loop; +end; +$$; +-- Ensure we get a result cache on the inner side of the nested loop +SET enable_hashjoin TO off; +SET enable_bitmapscan TO off; +SELECT explain_resultcache(' +SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 +INNER JOIN tenk1 t2 ON t1.unique1 = t2.twenty +WHERE t2.unique1 < 1000;', false); + explain_resultcache +-------------------------------------------------------------------------------------------- + Aggregate (actual rows=1 loops=1) + -> Nested Loop (actual rows=1000 loops=1) + -> Seq Scan on tenk1 t2 (actual rows=1000 loops=1) + Filter: (unique1 < 1000) + Rows Removed by Filter: 9000 + -> Result Cache (actual rows=1 loops=1000) + Cache Key: t2.twenty + Hits: 980 Misses: 20 Evictions: Zero Overflows: 0 Memory Usage: NkB + -> Index Only Scan using tenk1_unique1 on tenk1 t1 (actual rows=1 loops=20) + Index Cond: (unique1 = t2.twenty) + Heap Fetches: N +(11 rows) + +-- And check we get the expected results. +SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 +INNER JOIN tenk1 t2 ON t1.unique1 = t2.twenty +WHERE t2.unique1 < 1000; + count | avg +-------+-------------------- + 1000 | 9.5000000000000000 +(1 row) + +-- Try with LATERAL joins +SELECT explain_resultcache(' +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000;', false); + explain_resultcache +-------------------------------------------------------------------------------------------- + Aggregate (actual rows=1 loops=1) + -> Nested Loop (actual rows=1000 loops=1) + -> Seq Scan on tenk1 t1 (actual rows=1000 loops=1) + Filter: (unique1 < 1000) + Rows Removed by Filter: 9000 + -> Result Cache (actual rows=1 loops=1000) + Cache Key: t1.twenty + Hits: 980 Misses: 20 Evictions: Zero Overflows: 0 Memory Usage: NkB + -> Index Only Scan using tenk1_unique1 on tenk1 t2 (actual rows=1 loops=20) + Index Cond: (unique1 = t1.twenty) + Heap Fetches: N +(11 rows) + +-- And check we get the expected results. +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000; + count | avg +-------+-------------------- + 1000 | 9.5000000000000000 +(1 row) + +-- Reduce work_mem so that we see some cache evictions +SET work_mem TO '64kB'; +SET enable_mergejoin TO off; +-- Ensure we get some evictions. We're unable to validate the hits and misses +-- here as the number of entries that fit in the cache at once will vary +-- between different machines. +SELECT explain_resultcache(' +SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 +INNER JOIN tenk1 t2 ON t1.unique1 = t2.thousand +WHERE t2.unique1 < 1200;', true); + explain_resultcache +---------------------------------------------------------------------------------------------- + Aggregate (actual rows=1 loops=1) + -> Nested Loop (actual rows=1200 loops=1) + -> Seq Scan on tenk1 t2 (actual rows=1200 loops=1) + Filter: (unique1 < 1200) + Rows Removed by Filter: 8800 + -> Result Cache (actual rows=1 loops=1200) + Cache Key: t2.thousand + Hits: N Misses: N Evictions: N Overflows: 0 Memory Usage: NkB + -> Index Only Scan using tenk1_unique1 on tenk1 t1 (actual rows=1 loops=1028) + Index Cond: (unique1 = t2.thousand) + Heap Fetches: N +(11 rows) + +RESET enable_mergejoin; +RESET work_mem; +RESET enable_bitmapscan; +RESET enable_hashjoin; +-- Test parallel plans with Result Cache. +SET min_parallel_table_scan_size TO 0; +SET parallel_setup_cost TO 0; +SET parallel_tuple_cost TO 0; +SET max_parallel_workers_per_gather TO 2; +-- Ensure we get a parallel plan. +EXPLAIN (COSTS OFF) +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000; + QUERY PLAN +------------------------------------------------------------------------------- + Finalize Aggregate + -> Gather + Workers Planned: 2 + -> Partial Aggregate + -> Nested Loop + -> Parallel Bitmap Heap Scan on tenk1 t1 + Recheck Cond: (unique1 < 1000) + -> Bitmap Index Scan on tenk1_unique1 + Index Cond: (unique1 < 1000) + -> Result Cache + Cache Key: t1.twenty + -> Index Only Scan using tenk1_unique1 on tenk1 t2 + Index Cond: (unique1 = t1.twenty) +(13 rows) + +-- And ensure the parallel plan gives us the correct results. +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000; + count | avg +-------+-------------------- + 1000 | 9.5000000000000000 +(1 row) + +RESET max_parallel_workers_per_gather; +RESET parallel_tuple_cost; +RESET parallel_setup_cost; +RESET min_parallel_table_scan_size; diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index d5532d0ccc0..c7986fb7fcc 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -1091,19 +1091,21 @@ select sum(o.four), sum(ss.a) from select * from x ) ss where o.ten = 1; - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +--------------------------------------------------------- Aggregate -> Nested Loop -> Seq Scan on onek o Filter: (ten = 1) - -> CTE Scan on x - CTE x - -> Recursive Union - -> Result - -> WorkTable Scan on x x_1 - Filter: (a < 10) -(10 rows) + -> Result Cache + Cache Key: o.four + -> CTE Scan on x + CTE x + -> Recursive Union + -> Result + -> WorkTable Scan on x x_1 + Filter: (a < 10) +(12 rows) select sum(o.four), sum(ss.a) from onek o cross join lateral ( diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out index 98dde452e62..0bb558d93c9 100644 --- a/src/test/regress/expected/sysviews.out +++ b/src/test/regress/expected/sysviews.out @@ -111,10 +111,11 @@ select name, setting from pg_settings where name like 'enable%'; enable_partition_pruning | on enable_partitionwise_aggregate | off enable_partitionwise_join | off + enable_resultcache | on enable_seqscan | on enable_sort | on enable_tidscan | on -(19 rows) +(20 rows) -- Test that the pg_timezone_names and pg_timezone_abbrevs views are -- more-or-less working. We can't test their contents in any great detail diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 312c11a4bd9..2e898390892 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -119,7 +119,7 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr # ---------- # Another group of parallel tests # ---------- -test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression +test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression resultcache # event triggers cannot run concurrently with any test that runs DDL # oidjoins is read-only, though, and should run late for best coverage diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 5a80bfacd88..a46f3d01789 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -203,6 +203,7 @@ test: partition_info test: tuplesort test: explain test: compression +test: resultcache test: event_trigger test: oidjoins test: fast_default diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index eb53668299c..eb80a2fe063 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -1098,9 +1098,11 @@ select v||'a', case when v||'a' = 'aa' then 1 else 0 end, count(*) -- Make sure that generation of HashAggregate for uniqification purposes -- does not lead to array overflow due to unexpected duplicate hash keys -- see CAFeeJoKKu0u+A_A9R9316djW-YW3-+Gtgvy3ju655qRHR3jtdA@mail.gmail.com +set enable_resultcache to off; explain (costs off) select 1 from tenk1 where (hundred, thousand) in (select twothousand, twothousand from onek); +reset enable_resultcache; -- -- Hash Aggregation Spill tests diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 8164383fb53..7f866c603b8 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -550,6 +550,7 @@ reset enable_nestloop; set work_mem to '64kB'; set enable_mergejoin to off; +set enable_resultcache to off; explain (costs off) select count(*) from tenk1 a, tenk1 b @@ -559,6 +560,7 @@ select count(*) from tenk1 a, tenk1 b reset work_mem; reset enable_mergejoin; +reset enable_resultcache; -- -- regression test for 8.2 bug with improper re-ordering of left joins diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 6ccb52ad1d6..247264f93b7 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -464,6 +464,9 @@ begin ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N'); ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N'); ln := regexp_replace(ln, 'Rows Removed by Filter: \d+', 'Rows Removed by Filter: N'); + ln := regexp_replace(ln, 'Hits: \d+', 'Hits: N'); + ln := regexp_replace(ln, 'Misses: \d+', 'Misses: N'); + ln := regexp_replace(ln, 'Memory Usage: \d+', 'Memory Usage: N'); return next ln; end loop; end; @@ -515,6 +518,7 @@ create index ab_a3_b3_a_idx on ab_a3_b3 (a); set enable_hashjoin = 0; set enable_mergejoin = 0; +set enable_resultcache = 0; select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(0, 0, 1)'); @@ -533,6 +537,7 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on reset enable_hashjoin; reset enable_mergejoin; +reset enable_resultcache; reset parallel_setup_cost; reset parallel_tuple_cost; reset min_parallel_table_scan_size; diff --git a/src/test/regress/sql/resultcache.sql b/src/test/regress/sql/resultcache.sql new file mode 100644 index 00000000000..2be5b8f2d88 --- /dev/null +++ b/src/test/regress/sql/resultcache.sql @@ -0,0 +1,91 @@ +-- Perform tests on the Result Cache node. + +-- The cache hits/misses/evictions from the Result Cache node can vary between +-- machines. Let's just replace the number with an 'N'. In order to allow us +-- to perform validation when the measure was zero, we replace a zero value +-- with "Zero". All other numbers are replaced with 'N'. +create function explain_resultcache(query text, hide_hitmiss bool) returns setof text +language plpgsql as +$$ +declare + ln text; +begin + for ln in + execute format('explain (analyze, costs off, summary off, timing off) %s', + query) + loop + if hide_hitmiss = true then + ln := regexp_replace(ln, 'Hits: 0', 'Hits: Zero'); + ln := regexp_replace(ln, 'Hits: \d+', 'Hits: N'); + ln := regexp_replace(ln, 'Misses: 0', 'Misses: Zero'); + ln := regexp_replace(ln, 'Misses: \d+', 'Misses: N'); + end if; + ln := regexp_replace(ln, 'Evictions: 0', 'Evictions: Zero'); + ln := regexp_replace(ln, 'Evictions: \d+', 'Evictions: N'); + ln := regexp_replace(ln, 'Memory Usage: \d+', 'Memory Usage: N'); + ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N'); + return next ln; + end loop; +end; +$$; + +-- Ensure we get a result cache on the inner side of the nested loop +SET enable_hashjoin TO off; +SET enable_bitmapscan TO off; +SELECT explain_resultcache(' +SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 +INNER JOIN tenk1 t2 ON t1.unique1 = t2.twenty +WHERE t2.unique1 < 1000;', false); + +-- And check we get the expected results. +SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 +INNER JOIN tenk1 t2 ON t1.unique1 = t2.twenty +WHERE t2.unique1 < 1000; + +-- Try with LATERAL joins +SELECT explain_resultcache(' +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000;', false); + +-- And check we get the expected results. +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000; + +-- Reduce work_mem so that we see some cache evictions +SET work_mem TO '64kB'; +SET enable_mergejoin TO off; +-- Ensure we get some evictions. We're unable to validate the hits and misses +-- here as the number of entries that fit in the cache at once will vary +-- between different machines. +SELECT explain_resultcache(' +SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 +INNER JOIN tenk1 t2 ON t1.unique1 = t2.thousand +WHERE t2.unique1 < 1200;', true); +RESET enable_mergejoin; +RESET work_mem; +RESET enable_bitmapscan; +RESET enable_hashjoin; + +-- Test parallel plans with Result Cache. +SET min_parallel_table_scan_size TO 0; +SET parallel_setup_cost TO 0; +SET parallel_tuple_cost TO 0; +SET max_parallel_workers_per_gather TO 2; + +-- Ensure we get a parallel plan. +EXPLAIN (COSTS OFF) +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000; + +-- And ensure the parallel plan gives us the correct results. +SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1, +LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1) t2 +WHERE t1.unique1 < 1000; + +RESET max_parallel_workers_per_gather; +RESET parallel_tuple_cost; +RESET parallel_setup_cost; +RESET min_parallel_table_scan_size; |
