更新
为了回应 Toni 在下面的评论,我尝试像在 python 中一样使用元组,它的效果比我原来的建议好得多。基于analyze 输出,隐式row(id1, id2) 与支持PK 的索引兼容。
select version();
version
----------------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 10.12 (Ubuntu 10.12-0ubuntu0.18.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0, 64-bit
(1 row)
explain analyze
select * from testidx_array
where (id1, id2) between (8, 150) and (9, 2000);
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on testidx_array (cost=423.81..1263.91 rows=19855 width=40) (actual time=1.772..4.148 rows=11851 loops=1)
Recheck Cond: ((ROW(id1, id2) >= ROW(8, 150)) AND (ROW(id1, id2) <= ROW(9, 2000)))
Heap Blocks: exact=54
-> Bitmap Index Scan on testidx_array_pkey (cost=0.00..418.84 rows=19855 width=0) (actual time=1.722..1.722 rows=11851 loops=1)
Index Cond: ((ROW(id1, id2) >= ROW(8, 150)) AND (ROW(id1, id2) <= ROW(9, 2000)))
Planning time: 0.096 ms
Execution time: 4.867 ms
(7 rows)
旧答案,以下,已被取代
您应该能够通过指定pk1 的范围然后为array[pk1, pk2] 条件包含and 来强制使用索引。
where pk1 between $first_pk1_value and $last_pk1_value
and array[pk1, pk2] between array[$first_pk1_value, $first_pk2_value]
and array[$last_pk1_value, $last_pk2_value]
这在测试表中对我有用:
\d testidx_array
Table "public.testidx_array"
Column | Type | Collation | Nullable | Default
----------+---------+-----------+----------+---------
id1 | integer | | not null |
id2 | integer | | not null |
somedata | text | | |
Indexes:
"testidx_array_pkey" PRIMARY KEY, btree (id1, id2)
explain analyze
select * from testidx_array
where array[id1, id2] between array[8,150] and array[9,2000];
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
Seq Scan on testidx_array (cost=0.00..1943.00 rows=500 width=40) (actual time=42.011..50.758 rows=11851 loops=1)
Filter: ((ARRAY[id1, id2] >= '{8,150}'::integer[]) AND (ARRAY[id1, id2] <= '{9,2000}'::integer[]))
Rows Removed by Filter: 88149
Planning time: 0.151 ms
Execution time: 51.325 ms
(5 rows)
explain analyze
select * from testidx_array
where id1 between 8 and 9
and array[id1, id2] between array[8,150] and array[9,2000];
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on testidx_array (cost=418.85..1258.91 rows=99 width=40) (actual time=2.278..11.109 rows=11851 loops=1)
Recheck Cond: ((id1 >= 8) AND (id1 <= 9))
Filter: ((ARRAY[id1, id2] >= '{8,150}'::integer[]) AND (ARRAY[id1, id2] <= '{9,2000}'::integer[]))
Rows Removed by Filter: 8149
Heap Blocks: exact=90
-> Bitmap Index Scan on testidx_array_pkey (cost=0.00..418.82 rows=19853 width=0) (actual time=2.138..2.138 rows=20000 loops=1)
Index Cond: ((id1 >= 8) AND (id1 <= 9))
Planning time: 0.289 ms
Execution time: 11.693 ms
(9 rows)