簡體   English   中英

如何讓 PostgreSQL 在謂詞中使用具有計算值的索引?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM