[英]How can I get PostgreSQL to use an index with a computed value in a predicate?
我的意思是這個。 在 PostgreSQL (v 15.1) 中,我按以下方式創建了一個表foo
。
create table foo (
id integer primary key generated by default as identity,
id_mod_7 int generated always as (id % 7) stored
);
create index on foo (id_mod_7, id);
insert into foo (id) select generate_series(1, 10000);
如果我使用不使用文字常量而是使用 function 的謂詞查詢此表,則使用順序掃描:
explain analyze
select count(1) from foo where id_mod_7 = extract(dow from current_date);
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Aggregate (cost=245.12..245.13 rows=1 width=8) (actual time=7.218..7.219 rows=1 loops=1)
-> Seq Scan on foo (cost=0.00..245.00 rows=50 width=0) (actual time=0.020..7.028 rows=1428 loops=1)
Filter: ((id_mod_7)::numeric = EXTRACT(dow FROM CURRENT_DATE))
Rows Removed by Filter: 8572
Planning Time: 0.178 ms
Execution Time: 7.281 ms
但是,如果我使用確實使用文字常量的謂詞查詢此表,則會使用索引掃描:
explain analyze
select count(1) from foo where id_mod_7 = 6;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=48.84..48.85 rows=1 width=8) (actual time=0.321..0.322 rows=1 loops=1)
-> Index Only Scan using foo_id_mod_7_id_idx on foo (cost=0.29..45.27 rows=1428 width=0) (actual time=0.022..0.214 rows=1428 loops=1)
Index Cond: (id_mod_7 = 6)
Heap Fetches: 0
Planning Time: 0.106 ms
Execution Time: 0.397 ms
我想如果我使用公用表表達式 (CTE) 的緩存(據稱?)屬性,也許我可以欺騙它使用索引,但無濟於事:
explain analyze
with param as (select extract(dow from current_date) as dow)
select count(1) from foo join param on id_mod_7 = dow;
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Aggregate (cost=245.12..245.13 rows=1 width=8) (actual time=5.830..5.831 rows=1 loops=1)
-> Seq Scan on foo (cost=0.00..245.00 rows=50 width=0) (actual time=0.025..5.668 rows=1428 loops=1)
Filter: ((id_mod_7)::numeric = EXTRACT(dow FROM CURRENT_DATE))
Rows Removed by Filter: 8572
Planning Time: 0.234 ms
Execution Time: 5.894 ms
這不是致命的,但我只是想了解這里發生了什么。 謝謝!
PS,為了避免混淆,它不是在 SQL 查詢中計算的表列。 它是(或將要)在 SQL 查詢中計算的謂詞表達式中的值。
就像我說的,我嘗試過使用 CTE,因為我相信 CTE 會被緩存或具體化,並期望進行索引掃描,但不幸的是仍然進行了順序掃描。
這是因為extract()
返回一個數值,但是該列是一個 integer。您可以在執行計划中看到這個效果: (id_mod_7)::numeric =...
- 該列需要轉換為數字才能能夠匹配extract()
中的值 function
您需要將extract()
function 的結果轉換為 int:
select count(*)
from foo
where id_mod_7 = extract(dow from current_date)::int
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.