From 7255d3ff7753d97337098a0967dcb4ffe3886864 Mon Sep 17 00:00:00 2001 From: Nikita Glukhov Date: Fri, 30 Nov 2018 14:56:54 +0300 Subject: [PATCH 7/7] Add regression tests for kNN btree --- src/test/regress/expected/btree_index.out | 779 ++++++++++++++++++++++++++++++ src/test/regress/sql/btree_index.sql | 232 +++++++++ 2 files changed, 1011 insertions(+) diff --git a/src/test/regress/expected/btree_index.out b/src/test/regress/expected/btree_index.out index 0bd48dc..a8ed9da 100644 --- a/src/test/regress/expected/btree_index.out +++ b/src/test/regress/expected/btree_index.out @@ -179,3 +179,782 @@ select reloptions from pg_class WHERE oid = 'btree_idx1'::regclass; {vacuum_cleanup_index_scale_factor=70.0} (1 row) +--- +--- Test B-tree distance ordering +--- +SET enable_bitmapscan = OFF; +-- temporarily disable bt_i4_index index on bt_i4_heap(seqno) +UPDATE pg_index SET indisvalid = false WHERE indexrelid = 'bt_i4_index'::regclass; +CREATE INDEX bt_i4_heap_random_idx ON bt_i4_heap USING btree(random, seqno); +-- test unsupported orderings (by non-first index attribute or by more than one order keys) +EXPLAIN (COSTS OFF) SELECT * FROM bt_i4_heap ORDER BY seqno <-> 0; + QUERY PLAN +------------------------------ + Sort + Sort Key: ((seqno <-> 0)) + -> Seq Scan on bt_i4_heap +(3 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM bt_i4_heap ORDER BY random <-> 0, seqno <-> 0; + QUERY PLAN +----------------------------------------------- + Sort + Sort Key: ((random <-> 0)), ((seqno <-> 0)) + -> Seq Scan on bt_i4_heap +(3 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM bt_i4_heap ORDER BY random <-> 0, random <-> 1; + QUERY PLAN +------------------------------------------------ + Sort + Sort Key: ((random <-> 0)), ((random <-> 1)) + -> Seq Scan on bt_i4_heap +(3 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 4000000; + QUERY PLAN +------------------------------------------------------------------------------- + Index Only Scan using bt_i4_heap_random_idx on bt_i4_heap + Index Cond: ((random > 1000000) AND (ROW(random, seqno) < ROW(6000000, 0))) + Order By: (random <-> 4000000) +(3 rows) + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 4000000; + seqno | random +-------+--------- + 6448 | 4157193 + 9004 | 3783884 + 4408 | 4488889 + 8391 | 4825069 + 8984 | 3148979 + 1829 | 3053937 + 6262 | 3013326 + 5380 | 3000193 + 9142 | 2847247 + 8411 | 2809541 + 2859 | 5224694 + 6320 | 5257716 + 2126 | 2648497 + 8729 | 5450460 + 6862 | 5556001 + 1836 | 5593978 + 2681 | 2321799 + 2893 | 1919087 + 210 | 1809552 +(19 rows) + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 10000000; + seqno | random +-------+--------- + 1836 | 5593978 + 6862 | 5556001 + 8729 | 5450460 + 6320 | 5257716 + 2859 | 5224694 + 8391 | 4825069 + 4408 | 4488889 + 6448 | 4157193 + 9004 | 3783884 + 8984 | 3148979 + 1829 | 3053937 + 6262 | 3013326 + 5380 | 3000193 + 9142 | 2847247 + 8411 | 2809541 + 2126 | 2648497 + 2681 | 2321799 + 2893 | 1919087 + 210 | 1809552 +(19 rows) + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 0; + seqno | random +-------+--------- + 210 | 1809552 + 2893 | 1919087 + 2681 | 2321799 + 2126 | 2648497 + 8411 | 2809541 + 9142 | 2847247 + 5380 | 3000193 + 6262 | 3013326 + 1829 | 3053937 + 8984 | 3148979 + 9004 | 3783884 + 6448 | 4157193 + 4408 | 4488889 + 8391 | 4825069 + 2859 | 5224694 + 6320 | 5257716 + 8729 | 5450460 + 6862 | 5556001 + 1836 | 5593978 +(19 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM bt_i4_heap +WHERE + random > 1000000 AND (random, seqno) < (6000000, 0) AND + random IN (1809552, 1919087, 2321799, 2648497, 3000193, 3013326, 4157193, 4488889, 5257716, 5593978, NULL) +ORDER BY random <-> 3000000; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Index Only Scan using bt_i4_heap_random_idx on bt_i4_heap + Index Cond: ((random > 1000000) AND (ROW(random, seqno) < ROW(6000000, 0)) AND (random = ANY ('{1809552,1919087,2321799,2648497,3000193,3013326,4157193,4488889,5257716,5593978,NULL}'::integer[]))) + Order By: (random <-> 3000000) +(3 rows) + +SELECT * FROM bt_i4_heap +WHERE + random > 1000000 AND (random, seqno) < (6000000, 0) AND + random IN (1809552, 1919087, 2321799, 2648497, 3000193, 3013326, 4157193, 4488889, 5257716, 5593978, NULL) +ORDER BY random <-> 3000000; + seqno | random +-------+--------- + 5380 | 3000193 + 6262 | 3013326 + 2126 | 2648497 + 2681 | 2321799 + 2893 | 1919087 + 6448 | 4157193 + 210 | 1809552 + 4408 | 4488889 + 6320 | 5257716 + 1836 | 5593978 +(10 rows) + +DROP INDEX bt_i4_heap_random_idx; +CREATE INDEX bt_i4_heap_random_idx ON bt_i4_heap USING btree(random DESC, seqno); +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 4000000; + seqno | random +-------+--------- + 6448 | 4157193 + 9004 | 3783884 + 4408 | 4488889 + 8391 | 4825069 + 8984 | 3148979 + 1829 | 3053937 + 6262 | 3013326 + 5380 | 3000193 + 9142 | 2847247 + 8411 | 2809541 + 2859 | 5224694 + 6320 | 5257716 + 2126 | 2648497 + 8729 | 5450460 + 6862 | 5556001 + 1836 | 5593978 + 2681 | 2321799 + 2893 | 1919087 + 210 | 1809552 +(19 rows) + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 10000000; + seqno | random +-------+--------- + 1836 | 5593978 + 6862 | 5556001 + 8729 | 5450460 + 6320 | 5257716 + 2859 | 5224694 + 8391 | 4825069 + 4408 | 4488889 + 6448 | 4157193 + 9004 | 3783884 + 8984 | 3148979 + 1829 | 3053937 + 6262 | 3013326 + 5380 | 3000193 + 9142 | 2847247 + 8411 | 2809541 + 2126 | 2648497 + 2681 | 2321799 + 2893 | 1919087 + 210 | 1809552 +(19 rows) + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 0; + seqno | random +-------+--------- + 210 | 1809552 + 2893 | 1919087 + 2681 | 2321799 + 2126 | 2648497 + 8411 | 2809541 + 9142 | 2847247 + 5380 | 3000193 + 6262 | 3013326 + 1829 | 3053937 + 8984 | 3148979 + 9004 | 3783884 + 6448 | 4157193 + 4408 | 4488889 + 8391 | 4825069 + 2859 | 5224694 + 6320 | 5257716 + 8729 | 5450460 + 6862 | 5556001 + 1836 | 5593978 +(19 rows) + +DROP INDEX bt_i4_heap_random_idx; +-- test parallel KNN scan +-- Serializable isolation would disable parallel query, so explicitly use an +-- arbitrary other level. +BEGIN ISOLATION LEVEL REPEATABLE READ; +SET parallel_setup_cost = 0; +SET parallel_tuple_cost = 0; +SET min_parallel_table_scan_size = 0; +SET max_parallel_workers = 4; +SET max_parallel_workers_per_gather = 4; +SET cpu_operator_cost = 0; +RESET enable_indexscan; +CREATE TABLE bt_knn_test AS SELECT i * 10 AS i FROM generate_series(1, 1000000) i; +CREATE INDEX bt_knn_test_idx ON bt_knn_test (i); +ALTER TABLE bt_knn_test SET (parallel_workers = 4); +ANALYZE bt_knn_test; +EXPLAIN (COSTS OFF) +SELECT i FROM bt_knn_test WHERE i > 8000000; + QUERY PLAN +--------------------------------------------------------------------- + Gather + Workers Planned: 4 + -> Parallel Index Only Scan using bt_knn_test_idx on bt_knn_test + Index Cond: (i > 8000000) +(4 rows) + +CREATE TABLE bt_knn_test2 AS + SELECT row_number() OVER (ORDER BY i * 10 <-> 4000003) AS n, i * 10 AS i + FROM generate_series(1, 1000000) i; +EXPLAIN (COSTS OFF) +WITH bt_knn_test1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + ORDER BY i <-> 4000003 +) +SELECT * FROM bt_knn_test1 t1 JOIN bt_knn_test2 t2 USING (n) WHERE t1.i <> t2.i; + QUERY PLAN +----------------------------------------------------------------------------------- + Hash Join + Hash Cond: (t2.n = t1.n) + Join Filter: (t1.i <> t2.i) + CTE bt_knn_test1 + -> WindowAgg + -> Gather Merge + Workers Planned: 4 + -> Parallel Index Only Scan using bt_knn_test_idx on bt_knn_test + Order By: (i <-> 4000003) + -> Seq Scan on bt_knn_test2 t2 + -> Hash + -> CTE Scan on bt_knn_test1 t1 +(12 rows) + +WITH bt_knn_test1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + ORDER BY i <-> 4000003 +) +SELECT * FROM bt_knn_test1 t1 JOIN bt_knn_test2 t2 USING (n) WHERE t1.i <> t2.i; + n | i | i +---+---+--- +(0 rows) + +DROP TABLE bt_knn_test; +CREATE TABLE bt_knn_test AS SELECT i FROM generate_series(1, 10) i, generate_series(1, 100000) j; +CREATE INDEX bt_knn_test_idx ON bt_knn_test (i); +ALTER TABLE bt_knn_test SET (parallel_workers = 4); +ANALYZE bt_knn_test; +EXPLAIN (COSTS OFF) +WITH +t1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + WHERE i IN (3, 4, 7, 8, 2) + ORDER BY i <-> 4 +), +t2 AS ( + SELECT i * 100000 + j AS n, (ARRAY[4, 3, 2, 7, 8])[i + 1] AS i + FROM generate_series(0, 4) i, generate_series(1, 100000) j +) +SELECT * FROM t1 JOIN t2 USING (n) WHERE t1.i <> t2.i; + QUERY PLAN +----------------------------------------------------------------------------------- + Hash Join + Hash Cond: (t2.n = t1.n) + Join Filter: (t1.i <> t2.i) + CTE t1 + -> WindowAgg + -> Gather Merge + Workers Planned: 4 + -> Parallel Index Only Scan using bt_knn_test_idx on bt_knn_test + Index Cond: (i = ANY ('{3,4,7,8,2}'::integer[])) + Order By: (i <-> 4) + CTE t2 + -> Nested Loop + -> Function Scan on generate_series i + -> Function Scan on generate_series j + -> CTE Scan on t2 + -> Hash + -> CTE Scan on t1 +(17 rows) + +WITH +t1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + WHERE i IN (3, 4, 7, 8, 2) + ORDER BY i <-> 4 +), +t2 AS ( + SELECT i * 100000 + j AS n, (ARRAY[4, 3, 2, 7, 8])[i + 1] AS i + FROM generate_series(0, 4) i, generate_series(1, 100000) j +) +SELECT * FROM t1 JOIN t2 USING (n) WHERE t1.i <> t2.i; + n | i | i +---+---+--- +(0 rows) + +RESET parallel_setup_cost; +RESET parallel_tuple_cost; +RESET min_parallel_table_scan_size; +RESET max_parallel_workers; +RESET max_parallel_workers_per_gather; +RESET cpu_operator_cost; +ROLLBACK; +-- enable bt_i4_index index on bt_i4_heap(seqno) +UPDATE pg_index SET indisvalid = true WHERE indexrelid = 'bt_i4_index'::regclass; +CREATE TABLE tenk3 AS SELECT thousand, tenthous FROM tenk1; +INSERT INTO tenk3 VALUES (NULL, 1), (NULL, 2), (NULL, 3); +-- Test distance ordering by ASC index +CREATE INDEX tenk3_idx ON tenk3 USING btree(thousand, tenthous); +EXPLAIN (COSTS OFF) +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 998; + QUERY PLAN +----------------------------------------------------------- + Index Only Scan using tenk3_idx on tenk3 + Index Cond: (ROW(thousand, tenthous) >= ROW(997, 5000)) + Order By: (thousand <-> 998) +(3 rows) + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 998; + thousand | tenthous +----------+---------- + 998 | 998 + 998 | 1998 + 998 | 2998 + 998 | 3998 + 998 | 4998 + 998 | 5998 + 998 | 6998 + 998 | 7998 + 998 | 8998 + 998 | 9998 + 999 | 999 + 999 | 1999 + 999 | 2999 + 999 | 3999 + 999 | 4999 + 999 | 5999 + 999 | 6999 + 999 | 7999 + 999 | 8999 + 999 | 9999 + 997 | 9997 + 997 | 8997 + 997 | 7997 + 997 | 6997 + 997 | 5997 +(25 rows) + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 0; + thousand | tenthous +----------+---------- + 997 | 5997 + 997 | 6997 + 997 | 7997 + 997 | 8997 + 997 | 9997 + 998 | 998 + 998 | 1998 + 998 | 2998 + 998 | 3998 + 998 | 4998 + 998 | 5998 + 998 | 6998 + 998 | 7998 + 998 | 8998 + 998 | 9998 + 999 | 999 + 999 | 1999 + 999 | 2999 + 999 | 3999 + 999 | 4999 + 999 | 5999 + 999 | 6999 + 999 | 7999 + 999 | 8999 + 999 | 9999 +(25 rows) + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) AND thousand < 1000 +ORDER BY thousand <-> 10000; + thousand | tenthous +----------+---------- + 999 | 9999 + 999 | 8999 + 999 | 7999 + 999 | 6999 + 999 | 5999 + 999 | 4999 + 999 | 3999 + 999 | 2999 + 999 | 1999 + 999 | 999 + 998 | 9998 + 998 | 8998 + 998 | 7998 + 998 | 6998 + 998 | 5998 + 998 | 4998 + 998 | 3998 + 998 | 2998 + 998 | 1998 + 998 | 998 + 997 | 9997 + 997 | 8997 + 997 | 7997 + 997 | 6997 + 997 | 5997 +(25 rows) + +SELECT thousand, tenthous FROM tenk3 +ORDER BY thousand <-> 500 +OFFSET 9970; + thousand | tenthous +----------+---------- + 999 | 999 + 999 | 1999 + 999 | 2999 + 999 | 3999 + 999 | 4999 + 999 | 5999 + 999 | 6999 + 999 | 7999 + 999 | 8999 + 999 | 9999 + 1 | 9001 + 1 | 8001 + 1 | 7001 + 1 | 6001 + 1 | 5001 + 1 | 4001 + 1 | 3001 + 1 | 2001 + 1 | 1001 + 1 | 1 + 0 | 9000 + 0 | 8000 + 0 | 7000 + 0 | 6000 + 0 | 5000 + 0 | 4000 + 0 | 3000 + 0 | 2000 + 0 | 1000 + 0 | 0 + | 1 + | 2 + | 3 +(33 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk3 +WHERE thousand > 100 AND thousand < 800 AND + thousand = ANY(ARRAY[0, 123, 234, 345, 456, 678, 901, NULL]::int2[]) +ORDER BY thousand <-> 300::int8; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- + Index Only Scan using tenk3_idx on tenk3 + Index Cond: ((thousand > 100) AND (thousand < 800) AND (thousand = ANY ('{0,123,234,345,456,678,901,NULL}'::smallint[]))) + Order By: (thousand <-> '300'::bigint) +(3 rows) + +SELECT * FROM tenk3 +WHERE thousand > 100 AND thousand < 800 AND + thousand = ANY(ARRAY[0, 123, 234, 345, 456, 678, 901, NULL]::int2[]) +ORDER BY thousand <-> 300::int8; + thousand | tenthous +----------+---------- + 345 | 345 + 345 | 1345 + 345 | 2345 + 345 | 3345 + 345 | 4345 + 345 | 5345 + 345 | 6345 + 345 | 7345 + 345 | 8345 + 345 | 9345 + 234 | 234 + 234 | 1234 + 234 | 2234 + 234 | 3234 + 234 | 4234 + 234 | 5234 + 234 | 6234 + 234 | 7234 + 234 | 8234 + 234 | 9234 + 456 | 456 + 456 | 1456 + 456 | 2456 + 456 | 3456 + 456 | 4456 + 456 | 5456 + 456 | 6456 + 456 | 7456 + 456 | 8456 + 456 | 9456 + 123 | 123 + 123 | 1123 + 123 | 2123 + 123 | 3123 + 123 | 4123 + 123 | 5123 + 123 | 6123 + 123 | 7123 + 123 | 8123 + 123 | 9123 + 678 | 678 + 678 | 1678 + 678 | 2678 + 678 | 3678 + 678 | 4678 + 678 | 5678 + 678 | 6678 + 678 | 7678 + 678 | 8678 + 678 | 9678 +(50 rows) + +DROP INDEX tenk3_idx; +-- Test distance ordering by DESC index +CREATE INDEX tenk3_idx ON tenk3 USING btree(thousand DESC, tenthous); +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 998; + thousand | tenthous +----------+---------- + 998 | 998 + 998 | 1998 + 998 | 2998 + 998 | 3998 + 998 | 4998 + 998 | 5998 + 998 | 6998 + 998 | 7998 + 998 | 8998 + 998 | 9998 + 997 | 5997 + 997 | 6997 + 997 | 7997 + 997 | 8997 + 997 | 9997 + 999 | 9999 + 999 | 8999 + 999 | 7999 + 999 | 6999 + 999 | 5999 + 999 | 4999 + 999 | 3999 + 999 | 2999 + 999 | 1999 + 999 | 999 +(25 rows) + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 0; + thousand | tenthous +----------+---------- + 997 | 9997 + 997 | 8997 + 997 | 7997 + 997 | 6997 + 997 | 5997 + 998 | 9998 + 998 | 8998 + 998 | 7998 + 998 | 6998 + 998 | 5998 + 998 | 4998 + 998 | 3998 + 998 | 2998 + 998 | 1998 + 998 | 998 + 999 | 9999 + 999 | 8999 + 999 | 7999 + 999 | 6999 + 999 | 5999 + 999 | 4999 + 999 | 3999 + 999 | 2999 + 999 | 1999 + 999 | 999 +(25 rows) + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) AND thousand < 1000 +ORDER BY thousand <-> 10000; + thousand | tenthous +----------+---------- + 999 | 999 + 999 | 1999 + 999 | 2999 + 999 | 3999 + 999 | 4999 + 999 | 5999 + 999 | 6999 + 999 | 7999 + 999 | 8999 + 999 | 9999 + 998 | 998 + 998 | 1998 + 998 | 2998 + 998 | 3998 + 998 | 4998 + 998 | 5998 + 998 | 6998 + 998 | 7998 + 998 | 8998 + 998 | 9998 + 997 | 5997 + 997 | 6997 + 997 | 7997 + 997 | 8997 + 997 | 9997 +(25 rows) + +SELECT thousand, tenthous FROM tenk3 +ORDER BY thousand <-> 500 +OFFSET 9970; + thousand | tenthous +----------+---------- + 1 | 1 + 1 | 1001 + 1 | 2001 + 1 | 3001 + 1 | 4001 + 1 | 5001 + 1 | 6001 + 1 | 7001 + 1 | 8001 + 1 | 9001 + 999 | 9999 + 999 | 8999 + 999 | 7999 + 999 | 6999 + 999 | 5999 + 999 | 4999 + 999 | 3999 + 999 | 2999 + 999 | 1999 + 999 | 999 + 0 | 0 + 0 | 1000 + 0 | 2000 + 0 | 3000 + 0 | 4000 + 0 | 5000 + 0 | 6000 + 0 | 7000 + 0 | 8000 + 0 | 9000 + | 3 + | 2 + | 1 +(33 rows) + +DROP INDEX tenk3_idx; +DROP TABLE tenk3; +-- Test distance ordering on by-ref types +CREATE TABLE knn_btree_ts (ts timestamp); +INSERT INTO knn_btree_ts +SELECT timestamp '2017-05-03 00:00:00' + tenthous * interval '1 hour' +FROM tenk1; +CREATE INDEX knn_btree_ts_idx ON knn_btree_ts USING btree(ts); +SELECT ts, ts <-> timestamp '2017-05-01 00:00:00' FROM knn_btree_ts ORDER BY 2 LIMIT 20; + ts | ?column? +--------------------------+------------------- + Wed May 03 00:00:00 2017 | @ 2 days + Wed May 03 01:00:00 2017 | @ 2 days 1 hour + Wed May 03 02:00:00 2017 | @ 2 days 2 hours + Wed May 03 03:00:00 2017 | @ 2 days 3 hours + Wed May 03 04:00:00 2017 | @ 2 days 4 hours + Wed May 03 05:00:00 2017 | @ 2 days 5 hours + Wed May 03 06:00:00 2017 | @ 2 days 6 hours + Wed May 03 07:00:00 2017 | @ 2 days 7 hours + Wed May 03 08:00:00 2017 | @ 2 days 8 hours + Wed May 03 09:00:00 2017 | @ 2 days 9 hours + Wed May 03 10:00:00 2017 | @ 2 days 10 hours + Wed May 03 11:00:00 2017 | @ 2 days 11 hours + Wed May 03 12:00:00 2017 | @ 2 days 12 hours + Wed May 03 13:00:00 2017 | @ 2 days 13 hours + Wed May 03 14:00:00 2017 | @ 2 days 14 hours + Wed May 03 15:00:00 2017 | @ 2 days 15 hours + Wed May 03 16:00:00 2017 | @ 2 days 16 hours + Wed May 03 17:00:00 2017 | @ 2 days 17 hours + Wed May 03 18:00:00 2017 | @ 2 days 18 hours + Wed May 03 19:00:00 2017 | @ 2 days 19 hours +(20 rows) + +SELECT ts, ts <-> timestamp '2018-01-01 00:00:00' FROM knn_btree_ts ORDER BY 2 LIMIT 20; + ts | ?column? +--------------------------+------------ + Mon Jan 01 00:00:00 2018 | @ 0 + Mon Jan 01 01:00:00 2018 | @ 1 hour + Sun Dec 31 23:00:00 2017 | @ 1 hour + Mon Jan 01 02:00:00 2018 | @ 2 hours + Sun Dec 31 22:00:00 2017 | @ 2 hours + Mon Jan 01 03:00:00 2018 | @ 3 hours + Sun Dec 31 21:00:00 2017 | @ 3 hours + Mon Jan 01 04:00:00 2018 | @ 4 hours + Sun Dec 31 20:00:00 2017 | @ 4 hours + Mon Jan 01 05:00:00 2018 | @ 5 hours + Sun Dec 31 19:00:00 2017 | @ 5 hours + Mon Jan 01 06:00:00 2018 | @ 6 hours + Sun Dec 31 18:00:00 2017 | @ 6 hours + Mon Jan 01 07:00:00 2018 | @ 7 hours + Sun Dec 31 17:00:00 2017 | @ 7 hours + Mon Jan 01 08:00:00 2018 | @ 8 hours + Sun Dec 31 16:00:00 2017 | @ 8 hours + Mon Jan 01 09:00:00 2018 | @ 9 hours + Sun Dec 31 15:00:00 2017 | @ 9 hours + Mon Jan 01 10:00:00 2018 | @ 10 hours +(20 rows) + +DROP TABLE knn_btree_ts; +RESET enable_bitmapscan; diff --git a/src/test/regress/sql/btree_index.sql b/src/test/regress/sql/btree_index.sql index 21171f7..307f2f5 100644 --- a/src/test/regress/sql/btree_index.sql +++ b/src/test/regress/sql/btree_index.sql @@ -111,3 +111,235 @@ create index btree_idx_err on btree_test(a) with (vacuum_cleanup_index_scale_fac -- Simple ALTER INDEX alter index btree_idx1 set (vacuum_cleanup_index_scale_factor = 70.0); select reloptions from pg_class WHERE oid = 'btree_idx1'::regclass; + +--- +--- Test B-tree distance ordering +--- + +SET enable_bitmapscan = OFF; + +-- temporarily disable bt_i4_index index on bt_i4_heap(seqno) +UPDATE pg_index SET indisvalid = false WHERE indexrelid = 'bt_i4_index'::regclass; + +CREATE INDEX bt_i4_heap_random_idx ON bt_i4_heap USING btree(random, seqno); + +-- test unsupported orderings (by non-first index attribute or by more than one order keys) +EXPLAIN (COSTS OFF) SELECT * FROM bt_i4_heap ORDER BY seqno <-> 0; +EXPLAIN (COSTS OFF) SELECT * FROM bt_i4_heap ORDER BY random <-> 0, seqno <-> 0; +EXPLAIN (COSTS OFF) SELECT * FROM bt_i4_heap ORDER BY random <-> 0, random <-> 1; + +EXPLAIN (COSTS OFF) +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 4000000; + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 4000000; + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 10000000; + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 0; + +EXPLAIN (COSTS OFF) +SELECT * FROM bt_i4_heap +WHERE + random > 1000000 AND (random, seqno) < (6000000, 0) AND + random IN (1809552, 1919087, 2321799, 2648497, 3000193, 3013326, 4157193, 4488889, 5257716, 5593978, NULL) +ORDER BY random <-> 3000000; + +SELECT * FROM bt_i4_heap +WHERE + random > 1000000 AND (random, seqno) < (6000000, 0) AND + random IN (1809552, 1919087, 2321799, 2648497, 3000193, 3013326, 4157193, 4488889, 5257716, 5593978, NULL) +ORDER BY random <-> 3000000; + +DROP INDEX bt_i4_heap_random_idx; + +CREATE INDEX bt_i4_heap_random_idx ON bt_i4_heap USING btree(random DESC, seqno); + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 4000000; + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 10000000; + +SELECT * FROM bt_i4_heap +WHERE random > 1000000 AND (random, seqno) < (6000000, 0) +ORDER BY random <-> 0; + +DROP INDEX bt_i4_heap_random_idx; + +-- test parallel KNN scan + +-- Serializable isolation would disable parallel query, so explicitly use an +-- arbitrary other level. +BEGIN ISOLATION LEVEL REPEATABLE READ; + +SET parallel_setup_cost = 0; +SET parallel_tuple_cost = 0; +SET min_parallel_table_scan_size = 0; +SET max_parallel_workers = 4; +SET max_parallel_workers_per_gather = 4; +SET cpu_operator_cost = 0; + +RESET enable_indexscan; + +CREATE TABLE bt_knn_test AS SELECT i * 10 AS i FROM generate_series(1, 1000000) i; +CREATE INDEX bt_knn_test_idx ON bt_knn_test (i); +ALTER TABLE bt_knn_test SET (parallel_workers = 4); +ANALYZE bt_knn_test; + +EXPLAIN (COSTS OFF) +SELECT i FROM bt_knn_test WHERE i > 8000000; + +CREATE TABLE bt_knn_test2 AS + SELECT row_number() OVER (ORDER BY i * 10 <-> 4000003) AS n, i * 10 AS i + FROM generate_series(1, 1000000) i; + +EXPLAIN (COSTS OFF) +WITH bt_knn_test1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + ORDER BY i <-> 4000003 +) +SELECT * FROM bt_knn_test1 t1 JOIN bt_knn_test2 t2 USING (n) WHERE t1.i <> t2.i; + +WITH bt_knn_test1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + ORDER BY i <-> 4000003 +) +SELECT * FROM bt_knn_test1 t1 JOIN bt_knn_test2 t2 USING (n) WHERE t1.i <> t2.i; + +DROP TABLE bt_knn_test; +CREATE TABLE bt_knn_test AS SELECT i FROM generate_series(1, 10) i, generate_series(1, 100000) j; +CREATE INDEX bt_knn_test_idx ON bt_knn_test (i); +ALTER TABLE bt_knn_test SET (parallel_workers = 4); +ANALYZE bt_knn_test; + +EXPLAIN (COSTS OFF) +WITH +t1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + WHERE i IN (3, 4, 7, 8, 2) + ORDER BY i <-> 4 +), +t2 AS ( + SELECT i * 100000 + j AS n, (ARRAY[4, 3, 2, 7, 8])[i + 1] AS i + FROM generate_series(0, 4) i, generate_series(1, 100000) j +) +SELECT * FROM t1 JOIN t2 USING (n) WHERE t1.i <> t2.i; + +WITH +t1 AS ( + SELECT row_number() OVER () AS n, i + FROM bt_knn_test + WHERE i IN (3, 4, 7, 8, 2) + ORDER BY i <-> 4 +), +t2 AS ( + SELECT i * 100000 + j AS n, (ARRAY[4, 3, 2, 7, 8])[i + 1] AS i + FROM generate_series(0, 4) i, generate_series(1, 100000) j +) +SELECT * FROM t1 JOIN t2 USING (n) WHERE t1.i <> t2.i; + +RESET parallel_setup_cost; +RESET parallel_tuple_cost; +RESET min_parallel_table_scan_size; +RESET max_parallel_workers; +RESET max_parallel_workers_per_gather; +RESET cpu_operator_cost; + +ROLLBACK; + +-- enable bt_i4_index index on bt_i4_heap(seqno) +UPDATE pg_index SET indisvalid = true WHERE indexrelid = 'bt_i4_index'::regclass; + + +CREATE TABLE tenk3 AS SELECT thousand, tenthous FROM tenk1; + +INSERT INTO tenk3 VALUES (NULL, 1), (NULL, 2), (NULL, 3); + +-- Test distance ordering by ASC index +CREATE INDEX tenk3_idx ON tenk3 USING btree(thousand, tenthous); + +EXPLAIN (COSTS OFF) +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 998; + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 998; + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 0; + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) AND thousand < 1000 +ORDER BY thousand <-> 10000; + +SELECT thousand, tenthous FROM tenk3 +ORDER BY thousand <-> 500 +OFFSET 9970; + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk3 +WHERE thousand > 100 AND thousand < 800 AND + thousand = ANY(ARRAY[0, 123, 234, 345, 456, 678, 901, NULL]::int2[]) +ORDER BY thousand <-> 300::int8; + +SELECT * FROM tenk3 +WHERE thousand > 100 AND thousand < 800 AND + thousand = ANY(ARRAY[0, 123, 234, 345, 456, 678, 901, NULL]::int2[]) +ORDER BY thousand <-> 300::int8; + +DROP INDEX tenk3_idx; + +-- Test distance ordering by DESC index +CREATE INDEX tenk3_idx ON tenk3 USING btree(thousand DESC, tenthous); + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 998; + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) +ORDER BY thousand <-> 0; + +SELECT thousand, tenthous FROM tenk3 +WHERE (thousand, tenthous) >= (997, 5000) AND thousand < 1000 +ORDER BY thousand <-> 10000; + +SELECT thousand, tenthous FROM tenk3 +ORDER BY thousand <-> 500 +OFFSET 9970; + +DROP INDEX tenk3_idx; + +DROP TABLE tenk3; + +-- Test distance ordering on by-ref types +CREATE TABLE knn_btree_ts (ts timestamp); + +INSERT INTO knn_btree_ts +SELECT timestamp '2017-05-03 00:00:00' + tenthous * interval '1 hour' +FROM tenk1; + +CREATE INDEX knn_btree_ts_idx ON knn_btree_ts USING btree(ts); + +SELECT ts, ts <-> timestamp '2017-05-01 00:00:00' FROM knn_btree_ts ORDER BY 2 LIMIT 20; +SELECT ts, ts <-> timestamp '2018-01-01 00:00:00' FROM knn_btree_ts ORDER BY 2 LIMIT 20; + +DROP TABLE knn_btree_ts; + +RESET enable_bitmapscan; -- 2.7.4