支援的版本: 目前 (17) / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10

68.2. 多元統計範例 #

68.2.1. 函數相依性 #

可以使用一個非常簡單的資料集來演示多元相關性,即一個具有兩個欄位的表格,兩個欄位都包含相同的值

CREATE TABLE t (a INT, b INT);
INSERT INTO t SELECT i % 100, i % 100 FROM generate_series(1, 10000) s(i);
ANALYZE t;

第 14.2 節 所述,規劃器可以使用從 pg_class 取得的頁數和列數來確定 t 的基數

SELECT relpages, reltuples FROM pg_class WHERE relname = 't';

 relpages | reltuples
----------+-----------
       45 |     10000

資料分佈非常簡單;每個欄位中只有 100 個不同的值,且均勻分佈。

以下範例顯示了估計 a 欄位上的 WHERE 條件的結果

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1;
                                 QUERY PLAN
-------------------------------------------------------------------​------------
 Seq Scan on t  (cost=0.00..170.00 rows=100 width=8) (actual rows=100 loops=1)
   Filter: (a = 1)
   Rows Removed by Filter: 9900

規劃器檢查該條件並確定此子句的選擇性為 1%。透過比較此估計值和實際列數,我們可以看到該估計值非常準確(實際上是精確的,因為表格非常小)。將 WHERE 條件更改為使用 b 欄位,會產生相同的計畫。但是,請觀察如果我們將相同的條件套用到兩個欄位,並用 AND 組合它們會發生什麼

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1;
                                 QUERY PLAN
-------------------------------------------------------------------​----------
 Seq Scan on t  (cost=0.00..195.00 rows=1 width=8) (actual rows=100 loops=1)
   Filter: ((a = 1) AND (b = 1))
   Rows Removed by Filter: 9900

規劃器會分別估計每個條件的選擇性,得出與上述相同的 1% 估計值。然後它假設這些條件是獨立的,因此它將它們的選擇性相乘,產生僅 0.01% 的最終選擇性估計值。這是一個顯著的低估,因為符合條件的實際列數 (100) 高出兩個數量級。

可以透過建立統計資訊物件來修復此問題,該物件指示 ANALYZE 計算兩個欄位上的函數相依性多元統計資訊

CREATE STATISTICS stts (dependencies) ON a, b FROM t;
ANALYZE t;
EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1;
                                  QUERY PLAN
-------------------------------------------------------------------​------------
 Seq Scan on t  (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1)
   Filter: ((a = 1) AND (b = 1))
   Rows Removed by Filter: 9900

68.2.2. 多元 N-相異計數 #

當估計多個欄位的集合的基數時,例如由 GROUP BY 子句產生的群組數時,會發生類似的問題。當 GROUP BY 列出單個欄位時,n-相異估計值(顯示為 HashAggregate 節點傳回的估計列數)非常準確

EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a;
                                       QUERY PLAN
-------------------------------------------------------------------​----------------------
 HashAggregate  (cost=195.00..196.00 rows=100 width=12) (actual rows=100 loops=1)
   Group Key: a
   ->  Seq Scan on t  (cost=0.00..145.00 rows=10000 width=4) (actual rows=10000 loops=1)

但是,如果沒有多元統計資訊,則在 GROUP BY 中具有兩個欄位的查詢中的群組數估計值(如下列範例所示)會差一個數量級

EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b;
                                       QUERY PLAN
-------------------------------------------------------------------​-------------------------
 HashAggregate  (cost=220.00..230.00 rows=1000 width=16) (actual rows=100 loops=1)
   Group Key: a, b
   ->  Seq Scan on t  (cost=0.00..145.00 rows=10000 width=8) (actual rows=10000 loops=1)

透過重新定義統計資訊物件以包含兩個欄位的 n-相異計數,估計值會大大提高

DROP STATISTICS stts;
CREATE STATISTICS stts (dependencies, ndistinct) ON a, b FROM t;
ANALYZE t;
EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b;
                                       QUERY PLAN
-------------------------------------------------------------------​-------------------------
 HashAggregate  (cost=220.00..221.00 rows=100 width=16) (actual rows=100 loops=1)
   Group Key: a, b
   ->  Seq Scan on t  (cost=0.00..145.00 rows=10000 width=8) (actual rows=10000 loops=1)

68.2.3. MCV 清單 #

第 68.2.1 節 中所述,函數相依性是非常便宜且高效的統計資訊類型,但它們的主要限制是它們的整體性質(僅追蹤欄位層級的相依性,而不是個別欄位值之間的相依性)。

本節介紹了多元變體MCV(最常見值) 清單,是 第 68.1 節 中描述的每個欄位統計資訊的直接擴展。這些統計資訊透過儲存個別值來解決此限制,但自然地,在 ANALYZE 中建立統計資訊、儲存和規劃時間方面,成本更高。

讓我們再次看一下 第 68.2.1 節 中的查詢,但這次是使用在同一組欄位上建立的MCV清單(請務必刪除函數相依性,以確保規劃器使用新建立的統計資訊)。

DROP STATISTICS stts;
CREATE STATISTICS stts2 (mcv) ON a, b FROM t;
ANALYZE t;
EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1;
                                   QUERY PLAN
-------------------------------------------------------------------​------------
 Seq Scan on t  (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1)
   Filter: ((a = 1) AND (b = 1))
   Rows Removed by Filter: 9900

估計值與函數相依性的估計值一樣準確,這主要歸功於表格相當小,並且具有具有少量不同值的簡單分佈。在查看第二個查詢(函數相依性無法很好地處理)之前,讓我們先檢查一下MCV清單。

可以使用 pg_mcv_list_items 設定傳回函數來檢查MCV清單。

SELECT m.* FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid),
                pg_mcv_list_items(stxdmcv) m WHERE stxname = 'stts2';
 index |  values  | nulls | frequency | base_frequency
-------+----------+-------+-----------+----------------
     0 | {0, 0}   | {f,f} |      0.01 |         0.0001
     1 | {1, 1}   | {f,f} |      0.01 |         0.0001
   ...
    49 | {49, 49} | {f,f} |      0.01 |         0.0001
    50 | {50, 50} | {f,f} |      0.01 |         0.0001
   ...
    97 | {97, 97} | {f,f} |      0.01 |         0.0001
    98 | {98, 98} | {f,f} |      0.01 |         0.0001
    99 | {99, 99} | {f,f} |      0.01 |         0.0001
(100 rows)

這證實了這兩個欄位中有 100 個不同的組合,並且它們都同樣可能(每個組合的頻率為 1%)。基本頻率是從每個欄位的統計資訊計算得出的頻率,就像沒有多欄統計資訊一樣。如果任一欄位中有任何空值,則會在 nulls 欄位中識別出來。

在估計選擇性時,規劃器會將所有條件套用到MCV清單中的項目,然後將符合項目的頻率加總。請參閱 src/backend/statistics/mcv.c 中的 mcv_clauselist_selectivity 以取得詳細資訊。

與函數相依性相比,MCV清單有兩個主要優點。首先,該清單儲存實際值,可以決定哪些組合相容。

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10;
                                 QUERY PLAN
-------------------------------------------------------------------​--------
 Seq Scan on t  (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1)
   Filter: ((a = 1) AND (b = 10))
   Rows Removed by Filter: 10000

其次,MCV清單處理更廣泛的子句類型,而不僅僅是像函數相依性這樣的等式子句。例如,考慮一下同一個表格的以下範圍查詢

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a <= 49 AND b > 49;
                                QUERY PLAN
-------------------------------------------------------------------​--------
 Seq Scan on t  (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1)
   Filter: ((a <= 49) AND (b > 49))
   Rows Removed by Filter: 10000

提交更正

如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步說明的內容,請使用 此表單 報告文件問題。