[英]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;
它只能有效地將索引用於a
和b
。 這意味着DB會提取與a
和b
條件匹配的所有行,然后針對其余條件檢查每一行。
當您將c
上的過濾器更改為等於時,它會(潛在地)減少行(僅匹配a
和b
和c
那些行),然后針對d
過濾器檢查那些(更少)行。 在這種情況下,使用索引更為有效。
通常,PostgreSQL查詢計划程序會評估兩個選項:(1)使用索引; (2)做一個SeqScan。 對於兩者,它都計算成本值-成本值越高,預期的性能越差。 因此,它采用的是成本值較小的產品。 這是決定是否使用索引的方式,沒有固定的閾值。
最后,上面寫了“加一范圍條件”。 這意味着,如果您使用等號,它不僅可以以最有效的方式使用索引,而且可以在一個范圍內使用索引。
考慮到查詢中只有一個范圍條件,建議您像這樣更改索引:
create index i on t (a,b,d,c);
現在它可以有效地將a
和b
和d
上的過濾器與索引一起使用,只需要將行過濾掉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.