-- The cache hits/misses/evictions from the Memoize 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_memoize(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, buffers off) %s',
query) loop if hide_hitmiss = truethen
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');
ln := regexp_replace(ln, 'loops=\d+', 'loops=N');
ln := regexp_replace(ln, 'Index Searches: \d+', 'Index Searches: N'); return next ln;
end loop;
end;
$$;
-- Ensure we get a memoize node on the inner side of the nested loop SET enable_hashjoin TO off; SET enable_bitmapscan TO off;
SELECT explain_memoize(' SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 INNERJOIN 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 INNERJOIN tenk1 t2 ON t1.unique1 = t2.twenty WHERE t2.unique1 < 1000;
-- Try with LATERAL joins SELECT explain_memoize(' SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1,
LATERAL (SELECT t2.unique1 FROM tenk1 t2 WHERE t1.twenty = t2.unique1 OFFSET 0) 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 OFFSET 0) t2 WHERE t1.unique1 < 1000;
-- Try with LATERAL joins SELECT explain_memoize(' SELECT COUNT(*),AVG(t2.t1two) FROM tenk1 t1 LEFTJOIN
LATERAL ( SELECT t1.two as t1two, * FROM tenk1 t2 WHERE t2.unique1 < 4 OFFSET 0
) t2 ON t1.two = t2.two WHERE t1.unique1 < 10;', false);
-- And check we get the expected results. SELECT COUNT(*),AVG(t2.t1two) FROM tenk1 t1 LEFTJOIN
LATERAL ( SELECT t1.two as t1two, * FROM tenk1 t2 WHERE t2.unique1 < 4 OFFSET 0
) t2 ON t1.two = t2.two WHERE t1.unique1 < 10;
-- Try with LATERAL references within PlaceHolderVars SELECT explain_memoize(' SELECT COUNT(*), AVG(t1.twenty) FROM tenk1 t1 LEFTJOIN
LATERAL (SELECT t1.two+1AS c1, t2.unique1 AS c2 FROM tenk1 t2) s ONTRUE WHERE s.c1 = s.c2 AND t1.unique1 < 1000;', false);
-- And check we get the expected results. SELECT COUNT(*), AVG(t1.twenty) FROM tenk1 t1 LEFTJOIN
LATERAL (SELECT t1.two+1AS c1, t2.unique1 AS c2 FROM tenk1 t2) s ONTRUE WHERE s.c1 = s.c2 AND t1.unique1 < 1000;
-- Ensure we do not omit the cache keys from PlaceHolderVars SELECT explain_memoize(' SELECT COUNT(*), AVG(t1.twenty) FROM tenk1 t1 LEFTJOIN
LATERAL (SELECT t1.twenty AS c1, t2.unique1 AS c2, t2.two FROM tenk1 t2) s ON t1.two = s.two WHERE s.c1 = s.c2 AND t1.unique1 < 1000;', false);
-- And check we get the expected results. SELECT COUNT(*), AVG(t1.twenty) FROM tenk1 t1 LEFTJOIN
LATERAL (SELECT t1.twenty AS c1, t2.unique1 AS c2, t2.two FROM tenk1 t2) s ON t1.two = s.two WHERE s.c1 = s.c2 AND t1.unique1 < 1000;
SET enable_mergejoin TO off;
-- Test for varlena datatype with expr evaluation CREATETABLE expr_key (x numeric, t text); INSERTINTO expr_key (x, t) SELECT d1::numeric, d1::text FROM ( SELECT round((d / pi())::numeric, 7) AS d1 FROM generate_series(1, 20) AS d
) t;
-- duplicate rows so we get some cache hits INSERTINTO expr_key SELECT * FROM expr_key;
CREATEINDEX expr_key_idx_x_t ON expr_key (x, t);
VACUUM ANALYZE expr_key;
-- Ensure we get we get a cache miss and hit for each of the 20 distinct values SELECT explain_memoize(' SELECT * FROM expr_key t1 INNERJOIN expr_key t2 ON t1.x = t2.t::numericAND t1.t::numeric = t2.x;', false);
DROPTABLE expr_key;
-- Reduce work_mem and hash_mem_multiplier so that we see some cache evictions SET work_mem TO'64kB'; SET hash_mem_multiplier TO1.0; -- 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_memoize(' SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1 INNERJOIN tenk1 t2 ON t1.unique1 = t2.thousand WHERE t2.unique1 < 1200;', true);
-- Ensure memoize operates in logical mode SELECT explain_memoize(' SELECT * FROM flt f1 INNERJOIN flt f2 ON f1.f = f2.f;', false);
-- Ensure memoize operates in binary mode SELECT explain_memoize(' SELECT * FROM flt f1 INNERJOIN flt f2 ON f1.f >= f2.f;', false);
DROPTABLE flt;
-- Exercise Memoize in binary mode with a large fixed width type and a -- varlena type. CREATETABLE strtest (n name, t text); CREATEINDEX strtest_n_idx ON strtest (n); CREATEINDEX strtest_t_idx ON strtest (t); INSERTINTO strtest VALUES('one','one'),('two','two'),('three',repeat(fipshash('three'),100)); -- duplicate rows so we get some cache hits INSERTINTO strtest SELECT * FROM strtest; ANALYZE strtest;
-- Ensure we get 3 hits and 3 misses SELECT explain_memoize(' SELECT * FROM strtest s1 INNERJOIN strtest s2 ON s1.n >= s2.n;', false);
-- Ensure we get 3 hits and 3 misses SELECT explain_memoize(' SELECT * FROM strtest s1 INNERJOIN strtest s2 ON s1.t >= s2.t;', false);
DROPTABLE strtest;
-- Ensure memoize works with partitionwise join SET enable_partitionwise_join TOon;
CREATETABLE prt (a int) PARTITION BY RANGE(a); CREATETABLE prt_p1 PARTITION OF prt FORVALUESFROM (0) TO (10); CREATETABLE prt_p2 PARTITION OF prt FORVALUESFROM (10) TO (20); INSERTINTO prt VALUES (0), (0), (0), (0); INSERTINTO prt VALUES (10), (10), (10), (10); CREATEINDEX iprt_p1_a ON prt_p1 (a); CREATEINDEX iprt_p2_a ON prt_p2 (a); ANALYZE prt;
SELECT explain_memoize(' SELECT * FROM prt t1 INNERJOIN prt t2 ON t1.a = t2.a;', false);
-- Ensure memoize works with parameterized union-all Append path SET enable_partitionwise_join TO off;
SELECT explain_memoize(' SELECT * FROM prt_p1 t1 INNERJOIN
(SELECT * FROM prt_p1 UNIONALLSELECT * FROM prt_p2) t2 ON t1.a = t2.a;', false);
DROPTABLE prt;
RESET enable_partitionwise_join;
-- Exercise Memoize code that flushes the cache when a parameter changes which -- is not part of the cache key.
-- Ensure we get a Memoize plan EXPLAIN (COSTS OFF) SELECT unique1 FROM tenk1 t0 WHERE unique1 < 3 ANDEXISTS ( SELECT1FROM tenk1 t1 INNERJOIN tenk1 t2 ON t1.unique1 = t2.hundred WHERE t0.ten = t1.twenty AND t0.two <> t2.four OFFSET 0);
-- Ensure the above query returns the correct result SELECT unique1 FROM tenk1 t0 WHERE unique1 < 3 ANDEXISTS ( SELECT1FROM tenk1 t1 INNERJOIN tenk1 t2 ON t1.unique1 = t2.hundred WHERE t0.ten = t1.twenty AND t0.two <> t2.four OFFSET 0);
-- Test parallel plans with Memoize SET min_parallel_table_scan_size TO0; SET parallel_setup_cost TO0; SET parallel_tuple_cost TO0; SET max_parallel_workers_per_gather TO2;
-- 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;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.1Bemerkung:
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.