2011-12-19 17 views
7

我有一個關於(language_id,state)索引的單詞表。下面是解釋結果分析一下:在Postgres中使用LIMIT時不使用索引

無限制

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL); 

Bitmap Heap Scan on words (cost=10800.38..134324.10 rows=441257 width=96) (actual time=233.257..416.026 rows=540556 loops=1) 
Recheck Cond: ((language_id = 27) AND (state IS NULL)) 
-> Bitmap Index Scan on ls (cost=0.00..10690.07 rows=441257 width=0) (actual time=230.849..230.849 rows=540556 loops=1) 
Index Cond: ((language_id = 27) AND (state IS NULL)) 
Total runtime: 460.277 ms 
(5 rows) 

限額100

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL) LIMIT 100; 

Limit (cost=0.00..51.66 rows=100 width=96) (actual time=0.081..0.184 rows=100 loops=1) 
-> Seq Scan on words (cost=0.00..227935.59 rows=441257 width=96) (actual time=0.080..0.160 rows=100 loops=1) 
Filter: ((state IS NULL) AND (language_id = 27)) 
Total runtime: 0.240 ms 
(4 rows) 

這究竟是爲什麼?我怎樣才能在所有情況下使用索引?

謝謝。

+4

沒有ORDER BY的LIMIT似乎是有限的(沒有雙關語意)值。您希望返回哪100行? – 2011-12-19 20:15:24

+0

BTW:language_id = 17 AND status IS NULL子句的選擇性是什麼?單詞表的總大小是多少? – wildplasser 2011-12-19 20:28:39

+0

true ...訂單發生在id DESC上。這可能會減慢它?該列需要索引嗎? @wildplasser總大小爲1,000萬行,選擇性大約爲500,000行 – alste 2011-12-19 20:32:32

回答

7

我認爲PostreSQL查詢規劃者只是認爲在第二種情況 - 即使用LIMIT的情況下 - 它不值得應用索引,因爲它[限制]太小。所以這不是問題。

+0

你說得對,但我怎麼能避免這種情況?其實我正在使用jsonb杜松子酒指數,由於限制1這個指數沒有得到使用,並花費了大量的時間。 – Anurag 2016-03-30 17:42:00

0

這也奇怪兩個查詢返回不同數量的行。我想你已經插入了......呃,如果你做了一個子選擇呢?

select * from (select ...) limit 100; 
+1

「(5 rows)」指的是解釋計劃中的行數,而不是查詢返回的行數 – Anna 2014-12-30 21:52:42

3

沒有限制:行數= 540556個循環= 1總運行時間:460.277毫秒

隨着限制:行數= 100環= 1總運行時間:0.240毫秒

我沒有看到一個問題這裏。如果您的查詢產生500K行,則需要更多時間。

3

查看關於Using EXPLAINQuery Planning的PostgreSQL文檔。查詢計劃人員偏好對LIMIT 100案件中索引掃描的順序掃描的原因很簡單,因爲順序掃描更便宜。

查詢中沒有ORDER BY子句,因此規劃器可以與匹配過濾器條件的前100個(隨機)行一致。索引掃描需要首先讀取索引頁,然後讀取數據頁以獲取相應的行。順序掃描只需要讀取數據頁以獲取行。在您的案例表中,統計數據似乎表明有足夠(隨機)的行匹配過濾條件。連續頁面讀取獲得100行的成本被認爲比首先讀取索引然後獲取實際行成本便宜。當您提高限制或行數較少時,您可能會看到不同的計劃。

默認設置下規劃者認爲隨機頁面的閱讀成本(random_page_cost)讀取順序頁(seq_page_cost)的四倍成本。可以調整這些設置以調整查詢計劃(例如,當整個數據庫在RAM中時,隨機頁面讀取並不比連續頁面讀取更昂貴並且應該優選索引掃描)。

set enable_seqscan = [on | off] 
set enable_indexscan = [on | off] 

雖然可以啓用/禁用某些類型的掃描在全球基礎上本應只用於特設:您還可以通過啓用/禁用某些類型的掃描,例如,嘗試不同的查詢計劃調試或按會話進行故障排除。

在測試查詢計劃之前還運行VACUUM ANALYZE words,否則在測試之間運行的自動真空(autovaccum)可能會影響結果。