DO $x$ DECLARE
r record;
r2 record;
cond text;
idx_ctids tid[];
ss_ctids tid[];
count int;
plan_ok bool;
plan_line text;
BEGIN FOR r INSELECT colname, oper, typ, value[ordinality], matches[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
-- prepare the condition IF r.value ISNULLTHEN
cond := format('%I %s %L', r.colname, r.oper, r.value); ELSE
cond := format('%I %s %L::%s', r.colname, r.oper, r.value, r.typ);
END IF;
-- run the query using the brin index SET enable_seqscan = 0; SET enable_bitmapscan = 1;
plan_ok := false; FOR plan_line IN EXECUTE format($y$EXPLAINSELECT array_agg(ctid) FROM brintest WHERE %s $y$, cond) LOOP IF plan_line LIKE'%Bitmap Heap Scan on brintest%'THEN
plan_ok := true;
END IF;
END LOOP; IFNOT plan_ok THEN
RAISE WARNING 'did not get bitmap indexscan plan for %', r;
END IF;
EXECUTE format($y$SELECT array_agg(ctid) FROM brintest WHERE %s $y$, cond) INTO idx_ctids;
-- run the query using a seqscan SET enable_seqscan = 1; SET enable_bitmapscan = 0;
plan_ok := false; FOR plan_line IN EXECUTE format($y$EXPLAINSELECT array_agg(ctid) FROM brintest WHERE %s $y$, cond) LOOP IF plan_line LIKE'%Seq Scan on brintest%'THEN
plan_ok := true;
END IF;
END LOOP; IFNOT plan_ok THEN
RAISE WARNING 'did not get seqscan plan for %', r;
END IF;
EXECUTE format($y$SELECT array_agg(ctid) FROM brintest WHERE %s $y$, cond) INTO ss_ctids;
-- make sure both return the same results
count := array_length(idx_ctids, 1);
IFNOT (count = array_length(ss_ctids, 1) AND
idx_ctids @> ss_ctids AND
idx_ctids <@ ss_ctids) THEN -- report the results of each scan to make the differences obvious
RAISE WARNING 'something not right in %: count %', r, count; SET enable_seqscan = 1; SET enable_bitmapscan = 0; FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest WHERE ' || cond LOOP
RAISE NOTICE 'seqscan: %', r2;
END LOOP;
SET enable_seqscan = 0; SET enable_bitmapscan = 1; FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest WHERE ' || cond LOOP
RAISE NOTICE 'bitmapscan: %', r2;
END LOOP;
END IF;
-- make sure we found expected number of matches IF count != r.matches THEN RAISE WARNING 'unexpected number of results % for %', count, r; END IF;
END LOOP;
END;
$x$;
SELECT brin_desummarize_range('brinidx', 0);
VACUUM brintest; -- force a summarization cycle in brinidx
UPDATE brintest SET int8col = int8col * int4col; UPDATE brintest SET textcol = ''WHERE textcol ISNOTNULL;
-- Tests for brin_summarize_new_values SELECT brin_summarize_new_values('brintest'); -- error, not an index SELECT brin_summarize_new_values('tenk1_unique1'); -- error, not a BRIN index SELECT brin_summarize_new_values('brinidx'); -- ok, no change expected
-- Tests for brin_desummarize_range SELECT brin_desummarize_range('brinidx', -1); -- error, invalid range SELECT brin_desummarize_range('brinidx', 0); SELECT brin_desummarize_range('brinidx', 0); SELECT brin_desummarize_range('brinidx', 100000000);
-- Test brin_summarize_range CREATETABLE brin_summarize (
value int
) WITH (fillfactor=10, autovacuum_enabled=false); CREATEINDEX brin_summarize_idx ON brin_summarize USING brin (value) WITH (pages_per_range=2); -- Fill a few pages
DO $$ DECLARE curtid tid;
BEGIN LOOP INSERTINTO brin_summarize VALUES (1) RETURNING ctid INTO curtid; EXITWHEN curtid > tid '(2, 0)';
END LOOP;
END;
$$;
-- summarize one range SELECT brin_summarize_range('brin_summarize_idx', 0); -- nothing: already summarized SELECT brin_summarize_range('brin_summarize_idx', 1); -- summarize one range SELECT brin_summarize_range('brin_summarize_idx', 2); -- nothing: page doesn't exist in table SELECT brin_summarize_range('brin_summarize_idx', 4294967295); -- invalid block number values SELECT brin_summarize_range('brin_summarize_idx', -1); SELECT brin_summarize_range('brin_summarize_idx', 4294967296);
-- test value merging in add_value CREATETABLE brintest_2 (n numrange); CREATEINDEX brinidx_2 ON brintest_2 USING brin (n); INSERTINTO brintest_2 VALUES ('empty'); INSERTINTO brintest_2 VALUES (numrange(0, 2^1000::numeric)); INSERTINTO brintest_2 VALUES ('(-1, 0)');
-- test brin cost estimates behave sanely based on correlation of values CREATETABLE brin_test (a INT, b INT); INSERTINTO brin_test SELECT x/100,x%100FROM generate_series(1,10000) x(x); CREATEINDEX brin_test_a_idx ON brin_test USING brin (a) WITH (pages_per_range = 2); CREATEINDEX brin_test_b_idx ON brin_test USING brin (b) WITH (pages_per_range = 2);
VACUUM ANALYZE brin_test;
-- Ensure brin index is used when columns are perfectly correlated EXPLAIN (COSTS OFF) SELECT * FROM brin_test WHERE a = 1; -- Ensure brin index is not used when values are not correlated EXPLAIN (COSTS OFF) SELECT * FROM brin_test WHERE b = 1;
-- make sure data are properly de-toasted in BRIN index CREATETABLE brintest_3 (a text, b text, c text, d text);
-- long random strings (~2000 chars each, so ~6kB for min/max on two -- columns) to trigger toasting WITH rand_value AS (SELECT string_agg(fipshash(i::text),'') AS val FROM generate_series(1,60) s(i)) INSERTINTO brintest_3 SELECT val, val, val, val FROM rand_value;
CREATEINDEX brin_test_toast_idx ON brintest_3 USING brin (b, c); DELETEFROM brintest_3;
-- We need to wait a bit for all transactions to complete, so that the -- vacuum actually removes the TOAST rows. Creating an index concurrently -- is a one way to achieve that, because it does exactly such wait. CREATEINDEX CONCURRENTLY brin_test_temp_idx ON brintest_3(a); DROPINDEX brin_test_temp_idx;
-- vacuum the table, to discard TOAST data
VACUUM brintest_3;
-- retry insert with a different random-looking (but deterministic) value -- the value is different, and so should replace either min or max in the -- brin summary WITH rand_value AS (SELECT string_agg(fipshash((-i)::text),'') AS val FROM generate_series(1,60) s(i)) INSERTINTO brintest_3 SELECT val, val, val, val FROM rand_value;
-- now try some queries, accessing the brin index SET enable_seqscan = off;
EXPLAIN (COSTS OFF) SELECT * FROM brintest_3 WHERE b < '0';
SELECT * FROM brintest_3 WHERE b < '0';
DROPTABLE brintest_3;
RESET enable_seqscan;
-- test parallel build with immutable function. CREATETABLE brintest_expr (n int); CREATE FUNCTION brintest_func() RETURNS int LANGUAGE sql IMMUTABLE RETURN0;
BEGIN; SET LOCAL min_parallel_table_scan_size = 0; SET LOCAL max_parallel_maintenance_workers = 4; CREATEINDEX brintest_expr_idx ON brintest_expr USING brin (brintest_func()); COMMIT; DROPTABLE brintest_expr; DROP FUNCTION brintest_func();
-- test an unlogged table, mostly to get coverage of brinbuildempty CREATE UNLOGGED TABLE brintest_unlogged (n numrange); CREATEINDEX brinidx_unlogged ON brintest_unlogged USING brin (n); INSERTINTO brintest_unlogged VALUES (numrange(0, 2^1000::numeric)); DROPTABLE brintest_unlogged;
-- test that the insert optimization works if no rows end up inserted CREATETABLE brin_insert_optimization (a int); INSERTINTO brin_insert_optimization VALUES (1); CREATEINDEX brin_insert_optimization_idx ON brin_insert_optimization USING brin (a); UPDATE brin_insert_optimization SET a = a;
REINDEX INDEX CONCURRENTLY brin_insert_optimization_idx; DROPTABLE brin_insert_optimization;
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.1 Sekunden
(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.