Postgresql

除了索引之外,我還需要統計資訊嗎?

  • April 17, 2022

假設我有一張包含應該經過幾個步驟的圖像的表格:

CREATE TABLE images (filename text, extracted bool, cropped bool, resized bool);
   
INSERT INTO images (filename, extracted, cropped, resized)
VALUES
   ('foo', false, false, false),
   ('bar', true, false, false),
   ('baz', true, true, false),
   ('qux', true, true, true);

在某些時候,我有一個查詢來查找所有被裁剪但仍需要調整大小的圖像:

SELECT count(*) FROM images WHERE cropped AND NOT resized;

現在我相信使查詢快速的最好方法是部分索引:

CREATE INDEX ON images (cropped, resized) WHERE (cropped AND NOT resized);

我將其設為局部,因為這cropped AND NOT resized是一種相對罕見的狀態,而可能有數百萬張圖像已經完全處理,還有數百萬張圖像尚未裁剪。

我現在的問題是,除了索引之外,我還需要統計資訊嗎?

其中之一?

CREATE STATISTICS stat1 (dependencies) ON cropped, resized FROM images;
CREATE STATISTICS stat2 (ndistinct) ON cropped, resized FROM images;
CREATE STATISTICS stat3 (mcv) ON cropped, resized FROM images;
ANALYZE images;

我找到了我之前錯過的章節How the Planner Uses Statistics (或者更確切地說與Planner 使用的統計資訊混為一談),但它只討論瞭如何將統計資訊轉換為行估計。鑑於顯然沒有關於索引的統計數據,我不清楚如何選擇索引。

我的實驗表明,目前我似乎不需要這些統計數據來使用索引,但仍不清楚為什麼會這樣。在深入了解原始碼後,我想我可以回答我自己的問題。

本質上,使用索引的決定是btcostestimate()依次做出的genericcostestimate()

它有助於記住每個表可以使用哪些類型的統計資訊:

  • 元組數
  • 對於每一列:不同值的數量(有時稱為“基數”)
  • 對於每一列:最常見的值
  • 對於每一列:剩餘(不太常見)值的直方圖
  • 如果已配置:dependenciesstats(“A 列中有多少個值只有一個值出現在 B 列中。”)
  • 如果已配置:ndistinct統計資訊(A 和 B 列中唯一值組合的數量。)
  • 如果已配置:mcv統計資訊(A 和 B 列中最常見的值組合。)

對於每個索引,Postgres 確定可以使用索引檢查哪些條件(“索引條件”或“索引質量”)。基於這些,genericcostestimate()(使用clauselist_selectivity())計算索引的選擇性,同時考慮到那些擴展的統計數據。這實際上反映在我的實驗中,因為我通過以下mcv類型的擴展統計數據獲得了更好的行估計:

截屏

截屏

實際時間的差異取決於記憶體。

部分索引的謂詞也會被考慮在內,但前提是它引入了額外的限制,所以這裡不相關。

所以我認為如何選擇索引是這樣的:首先檢查索引謂詞以查看索引是否可用。然後計算特定條件的選擇性,如果沒有擴展統計數據,這確實有點錯誤。但再往下看,當計算實際成本時,它是如此之低,因為索引太小,以至於即使錯誤的行估計成本也非常低。

所以答案是肯定的,對於良好的行估計仍然需要理論上擴展的統計資訊,****但也不需要,仍然選擇沒有擴展統計資訊的索引,因為它太小了。

你在很大程度上想多了。您的查詢非常簡單,只有幾種方法可以執行。無論是返回 7000 行還是 2000 行,都無關緊要,因為無論哪種方式,索引似乎都比微不足道的替代方案要好。

如果您確實想要執行更多種類的查詢,這些查詢有更多機會做出錯誤的規劃器選擇,那麼包含 mcv 種類的擴展統計資訊可能很重要。

你的兩個例子完全不匹配。您問題中的計數表會導致行估計與您的答案中顯示的大不相同。如果沒有擴展的 MCV 統計資訊,它將提供大約 5,000,000,如果有擴展的統計資訊,它將提供大約 1。當然不是 6872 對 1782。

引用自:https://dba.stackexchange.com/questions/311006