簡體   English   中英

PostgreSQL:為什么此查詢不使用我的索引?

[英]PostgreSQL: Why is this query not using my index?

我正在數據庫上執行此查詢(所有數字和列名均已組成):

select * from t where a=1 and b=11 and c!=5 and d<8

t有一個索引:

create index i on t (a,b,c,d)

當我運行“ EXPLAIN ANALYZE”時,查詢將執行順序掃描,大約需要55毫秒才能完成此操作。 如果我這樣修改查詢:

select * from t where a=1 and b=11 and c=5 and d<8
                                       ^

它使用索引並在0.5毫秒內完成。 所以它一定是NOT EQUALS,對吧? 並非如此,因為如果執行此查詢:

select * from t where a=1 and b=11 and c=5 and d!=8
                                               ^

查詢仍然使用索引。 但是,如果我嘗試這樣做,則沒有索引:

select * from t where a=1 and b=11 and c<5 and d<8
                                       ^

那么為什么Postgres表現得如此? 這對我來說很奇怪。

我會說它不會在第一個查詢中使用索引,因為該索引實際上並沒有幫助,因為幾乎整個表都匹配。 在這種情況下,整個表的掃描速度更快。 最后兩個查詢之間的區別在於,僅在預期結果大小低於特定閾值的情況下才可能使用索引。 完全匹配的查詢產生的結果很可能少於使用小於的查詢,但產生的結果仍然少於等於選擇。

話雖如此,查詢優化器是一款非常復雜的軟件,通常會產生令人驚訝的結果。

正如您已經意識到的那樣,問題與使用除equals之外的其他運算符有關。 索引只能最有效地用於與等號(加上一個范圍條件)進行比較的最左邊的列。

在您的示例中:

create index i on t (a,b,c,d);
where a=1 and b=11 and c!=5 and d<8;

它只能有效地將索引用於ab 這意味着DB會提取與ab條件匹配的所有行,然后針對其余條件檢查每一行。

當您將c上的過濾器更改為等於時,它會(潛在地)減少行(僅匹配abc那些行),然后針對d過濾器檢查那些(更少)行。 在這種情況下,使用索引更為有效。

通常,PostgreSQL查詢計划程序會評估兩個選項:(1)使用索引; (2)做一個SeqScan。 對於兩者,它都計算成本值-成本值越高,預期的性能越差。 因此,它采用的是成本值較小的產品。 這是決定是否使用索引的方式,沒有固定的閾值。

最后,上面寫了“加一范圍條件”。 這意味着,如果您使用等號,它不僅可以以最有效的方式使用索引,而且可以在一個范圍內使用索引。

考慮到查詢中只有一個范圍條件,建議您像這樣更改索引:

create index i on t (a,b,d,c);

現在它可以有效地將abd上的過濾器與索引一起使用,只需要將行過濾掉c!=5 盡管此索引可以像原始索引一樣更有效地用於您的查詢,但這並不意味着PG會自動使用它。 這取決於成本估算。 但是嘗試一下。

最后,如果這不是快足夠多的5使用的是在表達c!=5是恆定的,你可能會考慮部分索引:

 create index i on t (a,b,d)
        where c!=5;

如果您將它們與之比較的值都是常量,那么您也可以對所有其他列執行此操作。

參考文獻:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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