2010-07-01 99 views
2

我有一個帶有2個外鍵的表,我們稱它們爲fk1和fk2。兩者具有相同的類型和相同的指數。但是當我「解釋」一個簡單的選擇查詢時,我會得到完全不同的查詢計劃。對於FK1:PostgreSql:具有相同列的不同查詢計劃

explain select * from mytable where fk1 = 1; 

結果

Index Scan using fk1_idx on mytable (cost=0.00..9.32 rows=2 width=4) 
    Index Cond: (fk1 = 1) 

對於FK2

explain select * from mytable where fk2 = 1; 

結果:

Bitmap Heap Scan on mytable (cost=5.88..659.18 rows=208 width=4) 
    Recheck Cond: (fk2 = 1) 
    -> Bitmap Index Scan on fk2_idx (cost=0.00..5.83 rows=208 width=0) 
     Index Cond: (fk2 = 1) 

第二個似乎更加低效。這是否是由於它可能會返回更多結果,因此更復雜的查詢會得到回報?

回答

5

是的,這歸結於所謂謂詞的「選擇性」(「where ...」從句)。

如果謂詞僅選擇表中的一小部分行,那麼通過隨意訪問表數據來單獨獲取每一行是有意義的,因爲只會獲取幾個頁面。

隨着要選擇的行數增加,位圖掃描變得更合適:索引用於確定表中哪些頁面是「有趣的」,然後按照它們放置的順序掃描這些頁面表格數據文件。這具有可以一起請求相鄰頁面的優點,這可能由文件系統/磁盤系統更有效地服務。 (當然,這取決於表格數據文件被合理地分解)。由於每個頁面中實際感興趣的元組集合並沒有被保留,只是一組頁面本身,所以必須爲檢索到的頁面中的每個元組重新評估謂詞:因此查詢中的「重新檢查cond」。 (這種策略的一個優點是它允許將多個獨立索引中的查找組合在一起,只需將(或ORing)來自多個索引查找的「感興趣的頁面」位圖結合起來)

由於要選擇的行數進一步增長,掃描索引的優勢縮小,因爲可能的結果是大多數表格將被標記爲「有趣」。所以最終一個簡單的順序掃描就變得合適了:所有的頁面都按順序走過,索引被忽略。

IIRC這往往表明,請求少於15%的表可能是索引掃描,15-50%位圖掃描,50%+ seq掃描。非常粗略。這很大程度上受random_page_cost和seq_page_cost等相關設置(例如effective_cache_size)的影響。

Postgresql收集有關常見值及其頻率的統計數據,以及數據庫中每列的其他值的直方圖 - 這用於估計選擇性並填充您在EXPLAIN輸出中看到的「行」估計值。該文檔包含如何完成該操作的說明:http://www.postgresql.org/docs/current/static/planner-stats-details.html

2

是的,查詢計劃將基於有關表中內容的統計數據。記得運行「真空分析」;不時地將統計數據保存至數據。

相關問題