13.2. 規劃器使用的統計訊息

就像我們在上一節裡展示的那樣,查詢規劃器需要估計一個查詢檢索的行的數目,這樣才能選擇正確的查詢規劃。 本節就系統用於這些估計的統計進行一些描述。

統計的一個部分就是每個資料表和索引中的記錄總數,以及每個資料表和索引佔據的磁盤塊數。 這個訊息保存在 pg_classreltuplesrelpages 字串中。我們可以用類似下面的查詢檢索這些訊息:

SELECT relname, relkind, reltuples, relpages FROM pg_class WHERE relname LIKE 'tenk1%';

    relname    | relkind | reltuples | relpages
---------------+---------+-----------+----------
 tenk1         | r       |     10000 |      233
 tenk1_hundred | i       |     10000 |       30
 tenk1_unique1 | i       |     10000 |       30
 tenk1_unique2 | i       |     10000 |       30
(4 rows)

我們在這裡可以看到 tenk1 有 10000 行, 它的索引也有這麼多行,但是索引遠比資料表小得多(很正常)。

出於效率考慮,reltuplesrelpages 不是實時更新的, 因此它們通常包含可能有些過時的數值。 它們被 VACUUMANALYZE,和幾個 DDL 命令,比如 CREATE INDEX 更新。一個獨立的 ANALYZE, 也就是沒有和 VACUUM 在一起的, 生成一個reltuples 的近似數值, 因為它並沒有讀取資料表裡的每一行。規劃器將把 pg_class 資料表裡面的數值調整為和目前的實際資料表尺寸匹配,以此獲取一個更接近的近似值。

大多數查詢只是檢索資料表中行的一部分,因為它們有限制待查行的 WHERE 子句。 因此規劃器需要對WHERE子句的選擇性(selectivity)進行評估, 選擇性也就是符合WHERE子句中每個條件的部分。 用於這個目的的訊息儲存在 pg_statistic 系統資料表中。 在 pg_statistic 中的記錄是由 ANALYZEVACUUM ANALYZE 命令更新的, 並且總是近似值,即使剛剛更新完也不例外。

除了直接查看 pg_statistic 之外, 我們手工檢查統計的時候最好查看它的視圖 pg_statspg_stats 設計成更具可讀性。 而且,pg_stats 是所有人都可以讀取的, 而 pg_statistic 只能由超級用戶讀取。 (這樣就可以避免非特權用戶從統計訊息中獲取一些和其他人的資料表內容相關的訊息。 pg_stats 視圖是受約束的,只顯示目前用戶可讀的資料表。) 比如,我們可以︰

SELECT attname, n_distinct, most_common_vals FROM pg_stats WHERE tablename = 'road';

 attname | n_distinct |                                                                                                                                                                                 most_common_vals                                                                                                                               

---------+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 name    |  -0.467008 | {"I- 580                        Ramp","I- 880                        Ramp","Sp Railroad                       ","I- 580                            ","I- 680                        Ramp","I- 80                         Ramp","14th                          St  ","5th                           St  ","Mission                       Blvd","I- 880                            "}
 thepath |         20 | {"[(-122.089,37.71),(-122.0886,37.711)]"}
(2 rows)

pg_statsSection 41.36 裡詳細描述。

pg_statistic 李儲存的訊息的數量,特別是 給每個字串用的 most_common_valshistogram_bounds 數組上的最大記錄數目可以用 ALTER TABLE SET STATISTICS 命令設置, 或者是用執行時參數 default_statistics_target 進行全局設置。 目前預設的限制是 10 個記錄。 提升該限制應該可以做出更準確的規劃器估計,特別是對那些有不規則資料分佈的字串而言, 付出的代價是在 pg_statistic 裡使用了更多空間,並且需要略微多一些的時間計算估計數值。 相比之下,比較低的限制可能更適合那些資料分佈比較簡單的字串。