-- throw in some NULL's and different values INSERTINTO brintest_multi (inetcol, cidrcol) SELECT
inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous FROM tenk1 ORDERBY thousand, tenthous LIMIT25;
-- test minmax-multi specific index options -- number of values must be >= 16 CREATEINDEX brinidx_multi ON brintest_multi USING brin (
int8col int8_minmax_multi_ops(values_per_range = 7)
); -- number of values must be <= 256 CREATEINDEX brinidx_multi ON brintest_multi USING brin (
int8col int8_minmax_multi_ops(values_per_range = 257)
);
-- first create an index with a single page range, to force compaction -- due to exceeding the number of values per summary CREATEINDEX brinidx_multi ON brintest_multi USING brin (
int8col int8_minmax_multi_ops,
int2col int2_minmax_multi_ops,
int4col int4_minmax_multi_ops,
oidcol oid_minmax_multi_ops,
tidcol tid_minmax_multi_ops,
float4col float4_minmax_multi_ops,
float8col float8_minmax_multi_ops,
macaddrcol macaddr_minmax_multi_ops,
macaddr8col macaddr8_minmax_multi_ops,
inetcol inet_minmax_multi_ops,
cidrcol inet_minmax_multi_ops,
datecol date_minmax_multi_ops,
timecol time_minmax_multi_ops,
timestampcol timestamp_minmax_multi_ops,
timestamptzcol timestamptz_minmax_multi_ops,
intervalcol interval_minmax_multi_ops,
timetzcol timetz_minmax_multi_ops,
numericcol numeric_minmax_multi_ops,
uuidcol uuid_minmax_multi_ops,
lsncol pg_lsn_minmax_multi_ops
);
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_multi, 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_multi WHERE %s $y$, cond) LOOP IF plan_line LIKE'%Bitmap Heap Scan on brintest_multi%'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_multi 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_multi WHERE %s $y$, cond) LOOP IF plan_line LIKE'%Seq Scan on brintest_multi%'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_multi 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_multi 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_multi 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_multi', 0);
VACUUM brintest_multi; -- force a summarization cycle in brinidx
-- Try inserting a values with NaN, to test distance calculation. insertinto public.brintest_multi (float4col) values (real'nan'); insertinto public.brintest_multi (float8col) values (real'nan');
UPDATE brintest_multi SET int8col = int8col * int4col;
-- Test handling of inet netmasks with inet_minmax_multi_ops CREATETABLE brin_test_inet (a inet); CREATEINDEXON brin_test_inet USING brin (a inet_minmax_multi_ops); INSERTINTO brin_test_inet VALUES ('127.0.0.1/0'); INSERTINTO brin_test_inet VALUES ('0.0.0.0/12'); DROPTABLE brin_test_inet;
-- Tests for brin_summarize_new_values SELECT brin_summarize_new_values('brintest_multi'); -- error, not an index SELECT brin_summarize_new_values('tenk1_unique1'); -- error, not a BRIN index SELECT brin_summarize_new_values('brinidx_multi'); -- ok, no change expected
-- Tests for brin_desummarize_range SELECT brin_desummarize_range('brinidx_multi', -1); -- error, invalid range SELECT brin_desummarize_range('brinidx_multi', 0); SELECT brin_desummarize_range('brinidx_multi', 0); SELECT brin_desummarize_range('brinidx_multi', 100000000);
-- test building an index with many values, to force compaction of the buffer CREATETABLE brin_large_range (a int4); INSERTINTO brin_large_range SELECT i FROM generate_series(1,10000) s(i); CREATEINDEX brin_large_range_idx ON brin_large_range USING brin (a int4_minmax_multi_ops); DROPTABLE brin_large_range;
-- Test brin_summarize_range CREATETABLE brin_summarize_multi (
value int
) WITH (fillfactor=10, autovacuum_enabled=false); CREATEINDEX brin_summarize_multi_idx ON brin_summarize_multi USING brin (value) WITH (pages_per_range=2); -- Fill a few pages
DO $$ DECLARE curtid tid;
BEGIN LOOP INSERTINTO brin_summarize_multi VALUES (1) RETURNING ctid INTO curtid; EXITWHEN curtid > tid '(2, 0)';
END LOOP;
END;
$$;
-- summarize one range SELECT brin_summarize_range('brin_summarize_multi_idx', 0); -- nothing: already summarized SELECT brin_summarize_range('brin_summarize_multi_idx', 1); -- summarize one range SELECT brin_summarize_range('brin_summarize_multi_idx', 2); -- nothing: page doesn't exist in table SELECT brin_summarize_range('brin_summarize_multi_idx', 4294967295); -- invalid block number values SELECT brin_summarize_range('brin_summarize_multi_idx', -1); SELECT brin_summarize_range('brin_summarize_multi_idx', 4294967296);
-- test brin cost estimates behave sanely based on correlation of values CREATETABLE brin_test_multi (a INT, b INT); INSERTINTO brin_test_multi SELECT x/100,x%100FROM generate_series(1,10000) x(x); CREATEINDEX brin_test_multi_a_idx ON brin_test_multi USING brin (a) WITH (pages_per_range = 2); CREATEINDEX brin_test_multi_b_idx ON brin_test_multi USING brin (b) WITH (pages_per_range = 2);
VACUUM ANALYZE brin_test_multi;
-- Ensure brin index is used when columns are perfectly correlated EXPLAIN (COSTS OFF) SELECT * FROM brin_test_multi WHERE a = 1; -- Ensure brin index is not used when values are not correlated EXPLAIN (COSTS OFF) SELECT * FROM brin_test_multi WHERE b = 1;
-- do some inequality tests CREATETABLE brin_test_multi_1 (a INT, b BIGINT) WITH (fillfactor=10); INSERTINTO brin_test_multi_1 SELECT i/5 + mod(911 * i + 483, 25),
i/10 + mod(751 * i + 221, 41) FROM generate_series(1,1000) s(i);
CREATEINDEX brin_test_multi_1_idx_1 ON brin_test_multi_1 USING brin (a int4_minmax_multi_ops) WITH (pages_per_range=5); CREATEINDEX brin_test_multi_1_idx_2 ON brin_test_multi_1 USING brin (b int8_minmax_multi_ops) WITH (pages_per_range=5);
SET enable_seqscan=off;
-- int: less than SELECT COUNT(*) FROM brin_test_multi_1 WHERE a < 37;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a < 113;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a <= 177;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a <= 25;
-- int: greater than SELECT COUNT(*) FROM brin_test_multi_1 WHERE a > 120;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a >= 180;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a > 71;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a >= 63;
-- int: equals SELECT COUNT(*) FROM brin_test_multi_1 WHERE a = 207;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a = 177;
-- bigint: less than SELECT COUNT(*) FROM brin_test_multi_1 WHERE b < 73;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b <= 47;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b < 199;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b <= 150;
-- bigint: greater than SELECT COUNT(*) FROM brin_test_multi_1 WHERE b > 93;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b > 37;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b >= 215;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b > 201;
-- bigint: equals SELECT COUNT(*) FROM brin_test_multi_1 WHERE b = 88;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b = 103;
-- now do the same, but insert the rows with the indexes already created -- so that we don't use the "build callback" and instead use the regular -- approach of adding rows into existing ranges
TRUNCATE brin_test_multi_1;
INSERTINTO brin_test_multi_1 SELECT i/5 + mod(911 * i + 483, 25),
i/10 + mod(751 * i + 221, 41) FROM generate_series(1,1000) s(i);
-- int: less than SELECT COUNT(*) FROM brin_test_multi_1 WHERE a < 37;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a < 113;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a <= 177;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a <= 25;
-- int: greater than SELECT COUNT(*) FROM brin_test_multi_1 WHERE a > 120;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a >= 180;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a > 71;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a >= 63;
-- int: equals SELECT COUNT(*) FROM brin_test_multi_1 WHERE a = 207;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE a = 177;
-- bigint: less than SELECT COUNT(*) FROM brin_test_multi_1 WHERE b < 73;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b <= 47;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b < 199;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b <= 150;
-- bigint: greater than SELECT COUNT(*) FROM brin_test_multi_1 WHERE b > 93;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b > 37;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b >= 215;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b > 201;
-- bigint: equals SELECT COUNT(*) FROM brin_test_multi_1 WHERE b = 88;
SELECT COUNT(*) FROM brin_test_multi_1 WHERE b = 103;
-- do some inequality tests for varlena data types CREATETABLE brin_test_multi_2 (a UUID) WITH (fillfactor=10); INSERTINTO brin_test_multi_2 SELECT v::uuid FROM (SELECT row_number() OVER (ORDERBY v) c, v FROM (SELECT fipshash((i/13)::text) AS v FROM generate_series(1,1000) s(i)) foo) bar ORDERBY c + 25 * random();
CREATEINDEX brin_test_multi_2_idx ON brin_test_multi_2 USING brin (a uuid_minmax_multi_ops) WITH (pages_per_range=5);
SET enable_seqscan=off;
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a < '3d914f93-48c9-cc0f-f8a7-9716700b9fcd';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a > '3d914f93-48c9-cc0f-f8a7-9716700b9fcd';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a <= 'f369cb89-fc62-7e66-8987-007d121ed1ea';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a >= 'aea92132-c4cb-eb26-3e6a-c2bf6c183b5d';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = '5feceb66-ffc8-6f38-d952-786c6d696c79';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = '86e50149-6586-6131-2a9e-0b35558d84f6';
-- now do the same, but insert the rows with the indexes already created -- so that we don't use the "build callback" and instead use the regular -- approach of adding rows into existing ranges
TRUNCATE brin_test_multi_2; INSERTINTO brin_test_multi_2 SELECT v::uuid FROM (SELECT row_number() OVER (ORDERBY v) c, v FROM (SELECT fipshash((i/13)::text) AS v FROM generate_series(1,1000) s(i)) foo) bar ORDERBY c + 25 * random();
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a < '3d914f93-48c9-cc0f-f8a7-9716700b9fcd';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a > '3d914f93-48c9-cc0f-f8a7-9716700b9fcd';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a <= 'f369cb89-fc62-7e66-8987-007d121ed1ea';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a >= 'aea92132-c4cb-eb26-3e6a-c2bf6c183b5d';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = '5feceb66-ffc8-6f38-d952-786c6d696c79';
SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = '86e50149-6586-6131-2a9e-0b35558d84f6';
-- test overflows during CREATE INDEX with extreme timestamp values CREATETABLE brin_timestamp_test(a TIMESTAMPTZ);
SET datestyle TO iso;
-- values close to timestamp minimum INSERTINTO brin_timestamp_test SELECT'4713-01-01 00:00:01 BC'::timestamptz + (i || ' seconds')::interval FROM generate_series(1,30) s(i);
-- values close to timestamp maximum INSERTINTO brin_timestamp_test SELECT'294276-12-01 00:00:01'::timestamptz + (i || ' seconds')::interval FROM generate_series(1,30) s(i);
CREATEINDEXON brin_timestamp_test USING brin (a timestamptz_minmax_multi_ops) WITH (pages_per_range=1); DROPTABLE brin_timestamp_test;
-- test overflows during CREATE INDEX with extreme date values CREATETABLE brin_date_test(a DATE);
-- insert values close to date minimum INSERTINTO brin_date_test SELECT'4713-01-01 BC'::date + i FROM generate_series(1, 30) s(i);
-- insert values close to date minimum INSERTINTO brin_date_test SELECT'5874897-12-01'::date + i FROM generate_series(1, 30) s(i);
CREATEINDEXON brin_date_test USING brin (a date_minmax_multi_ops) WITH (pages_per_range=1);
SET enable_seqscan = off;
-- make sure the ranges were built correctly and 2023-01-01 eliminates all EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF, BUFFERS OFF) SELECT * FROM brin_date_test WHERE a = '2023-01-01'::date;
DROPTABLE brin_date_test;
RESET enable_seqscan;
-- test handling of infinite timestamp values CREATETABLE brin_timestamp_test(a TIMESTAMP);
INSERTINTO brin_timestamp_test VALUES ('-infinity'), ('infinity'); INSERTINTO brin_timestamp_test SELECT i FROM generate_series('2000-01-01'::timestamp, '2000-02-09'::timestamp, '1 day'::interval) s(i);
CREATEINDEXON brin_timestamp_test USING brin (a timestamp_minmax_multi_ops) WITH (pages_per_range=1);
SET enable_seqscan = off;
EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF, BUFFERS OFF) SELECT * FROM brin_timestamp_test WHERE a = '2023-01-01'::timestamp;
EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF, BUFFERS OFF) SELECT * FROM brin_timestamp_test WHERE a = '1900-01-01'::timestamp;
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.