W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
如我們在上一節(jié)所見,查詢規(guī)劃器需要估計一個查詢要檢索的行數(shù),這樣才能對查詢計劃做出好的選擇。 本節(jié)對系統(tǒng)用于這些估計的統(tǒng)計信息進(jìn)行一個快速的介紹。
統(tǒng)計信息的一個部分就是每個表和索引中的項的總數(shù),以及每個表和索引占用的磁盤塊數(shù)。這些信息保存在pg_class
表的reltuples
和relpages
列中。
我們可以用類似下面的查詢查看這些信息:
SELECT relname, relkind, reltuples, relpages
FROM pg_class
WHERE relname LIKE 'tenk1%';
relname | relkind | reltuples | relpages
----------------------+---------+-----------+----------
tenk1 | r | 10000 | 358
tenk1_hundred | i | 10000 | 30
tenk1_thous_tenthous | i | 10000 | 30
tenk1_unique1 | i | 10000 | 30
tenk1_unique2 | i | 10000 | 30
(5 rows)
這里我們可以看到tenk1
包含 10000 行, 它的索引也有這么多行,但是索引遠(yuǎn)比表小得多(不奇怪)。
出于效率考慮,reltuples
和relpages
不是實時更新的 ,因此它們通常包含有些過時的值。它們被VACUUM
、ANALYZE
和幾個 DDL 命令(例如CREATE INDEX
)更新。一個不掃描全表的
VACUUM
或ANALYZE
操作(常見情況)將以它掃描的部分為基礎(chǔ)增量更新reltuples
計數(shù),這就導(dǎo)致了一個近似值。在任何情況中,規(guī)劃器將縮放它在pg_class
中找到的值來匹配當(dāng)前的物理表尺寸,這樣得到一個較緊的近似。
大多數(shù)查詢只是檢索表中行的一部分,因為它們有限制要被檢查的行的WHERE
子句。 因此規(guī)劃器需要估算WHERE
子句的選擇度,即符合WHERE
子句中每個條件的行的比例。 用于這個任務(wù)的信息存儲在pg_statistic
系統(tǒng)目錄中。 在pg_statistic
中的項由ANALYZE
和VACUUM ANALYZE
命令更新, 并且總是近似值(即使剛剛更新完)。
除了直接查看pg_statistic
之外, 手工檢查統(tǒng)計信息的時候最好查看它的視圖pg_stats
。pg_stats
被設(shè)計為更容易閱讀。 而且,pg_stats
是所有人都可以讀取的,而
pg_statistic
只能由超級用戶讀?。ㄟ@樣可以避免非授權(quán)用戶從統(tǒng)計信息中獲取一些其他人的表的內(nèi)容的信息。pg_stats
視圖被限制為只顯示當(dāng)前用戶可讀的表)。例如,我們可以:
SELECT attname, inherited, n_distinct,
array_to_string(most_common_vals, E'\n') as most_common_vals
FROM pg_stats
WHERE tablename = 'road';
attname | inherited | n_distinct | most_common_vals
---------+-----------+------------+------------------------------------
name | f | -0.363388 | I- 580 Ramp+
| | | I- 880 Ramp+
| | | Sp Railroad +
| | | I- 580 +
| | | I- 680 Ramp
name | t | -0.284859 | I- 880 Ramp+
| | | I- 580 Ramp+
| | | I- 680 Ramp+
| | | I- 580 +
| | | State Hwy 13 Ramp
(2 rows)
注意,這兩行顯示的是相同的列,一個對應(yīng)開始于road
表(inherited
=t
)的完全繼承層次, 另一個只包括road
表本身(inherited
=f
)。
ANALYZE
在pg_statistic
中存儲的信息量(特別是每個列的most_common_vals
中的最大項數(shù)和histogram_bounds
數(shù)組)可以用ALTER TABLE SET STATISTICS
命令為每一列設(shè)置,
或者通過設(shè)置配置變量default_statistics_target進(jìn)行全局設(shè)置。 目前的默認(rèn)限制是 100 個項。提升該限制可能會讓規(guī)劃器做出更準(zhǔn)確的估計(特別是對那些有不規(guī)則數(shù)據(jù)分布的列), 其代價是在pg_statistic
中消耗了更多空間,并且需要略微多一些的時間來計算估計數(shù)值。
相比之下,比較低的限制可能更適合那些數(shù)據(jù)分布比較簡單的列。
更多規(guī)劃器對統(tǒng)計信息的使用可參閱第 70 章。
常??梢钥吹接捎诓樵冏泳渲杏玫降亩鄠€列相互關(guān)聯(lián)而運行著糟糕的執(zhí)行計劃的慢查詢。規(guī)劃器通常會假設(shè)多個條件是彼此獨立的,這種假設(shè)在列值相互關(guān)聯(lián)的情況下是不成立的。由于常規(guī)的統(tǒng)計信息天然的針對個體列的性質(zhì),它們無法捕捉到跨列關(guān)聯(lián)的知識。不過,PostgreSQL有能力計算多元統(tǒng)計信息,它能捕捉這類信息。
由于可能的列組合數(shù)非常巨大,所以不可能自動計算多元統(tǒng)計信息??梢詣?chuàng)建擴展統(tǒng)計信息對象(更常被稱為統(tǒng)計信息對象)來指示服務(wù)器獲得跨感興趣列集合的統(tǒng)計信息。
統(tǒng)計信息對象可以使用CREATE STATISTICS命令創(chuàng)建。這樣一個對象的創(chuàng)建僅僅是創(chuàng)建了一個目錄項來表示對統(tǒng)計信息有興趣。實際的數(shù)據(jù)收集是由ANALYZE
(或者是一個手工命令,或者是后臺的自動分析)執(zhí)行的。收集到的值可以在
pg_statistic_ext_data
目錄中看到。
ANALYZE
基于它用來計算常規(guī)單列統(tǒng)計信息的表行樣本來計算擴展統(tǒng)計信息。由于樣本的尺寸會隨著表或者表列的統(tǒng)計信息目標(biāo)(如前一節(jié)所述)增大而增加,更大的統(tǒng)計信息目標(biāo)通常將會導(dǎo)致更準(zhǔn)確的擴展統(tǒng)計信息,同時也會導(dǎo)致更多花在計算擴展統(tǒng)計信息之上的時間。
下面的小節(jié)介紹當(dāng)前支持的擴展統(tǒng)計信息類型。
最簡單的一類擴展統(tǒng)計信息跟蹤函數(shù)依賴,這是在數(shù)據(jù)庫范式定義中使用的概念。如果列a
的值的知識足以決定列b
的值,即不會有兩個行具有相同的a
值但是有不同的b
值,我們就說列b
函數(shù)依賴于列
a
。在一個完全規(guī)范化的數(shù)據(jù)庫中,函數(shù)依賴應(yīng)該僅存在于主鍵和超鍵上。不過,實際上很多數(shù)據(jù)集合會由于各種原因無法被完全規(guī)范化,常見的例子是為了性能而有意地反規(guī)范化。即使在一個完全規(guī)范化的數(shù)據(jù)庫中,也會有某些列之間的部分關(guān)聯(lián),這些可以表達(dá)成部分函數(shù)依賴。
函數(shù)依賴的存在直接影響了特定查詢中估計的準(zhǔn)確性。如果一個查詢包含獨立列和依賴列上的條件,依賴列上的條件不會進(jìn)一步降低結(jié)果的尺寸。但是如果沒有函數(shù)依賴的知識,查詢規(guī)劃器將假定條件是獨立的,導(dǎo)致對結(jié)果尺寸的低估。
要告知規(guī)劃器有關(guān)函數(shù)依賴的信息,ANALYZE
可以收集跨列依賴的測度。評估所有列組之間的依賴程度可能會昂貴到不可實現(xiàn),因此數(shù)據(jù)收集被限制為針對那些在一個統(tǒng)計信息對象中一起出現(xiàn)的列組(用dependencies
選項定義)。建議只對強相關(guān)的列組創(chuàng)建dependencies
統(tǒng)計信息,以避免ANALYZE
以及后期查詢規(guī)劃中不必要的開銷。
這里是一個收集函數(shù)依賴統(tǒng)計信息的例子:
CREATE STATISTICS stts (dependencies) ON city, zip FROM zipcodes;
ANALYZE zipcodes;
SELECT stxname, stxkeys, stxddependencies
FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid)
WHERE stxname = 'stts';
stxname | stxkeys | stxddependencies
---------+---------+------------------------------------------
stts | 1 5 | {"1 => 5": 1.000000, "5 => 1": 0.423130}
(1 row)
這里可以看到列1(郵編)完全決定列5(城市),因此系數(shù)為1.0,而城市僅決定42%的郵編,意味著有很多城市(58%)有多個郵編。
在為涉及函數(shù)依賴列的查詢計算選擇度時,規(guī)劃器會使用依賴系數(shù)來調(diào)整針對條件的選擇度估計,這樣就不會產(chǎn)生低估。
當(dāng)前只有在考慮簡單等值條件(將列與常量值比較)和具有常量值的IN
子句時,函數(shù)依賴才適用。不會使用它們來改進(jìn)比較兩個列或者比較列和表達(dá)式的等值條件的估計, 也不會用它們來改進(jìn)范圍子句、LIKE
或者任何其他類型的條件。
在用函數(shù)依賴估計時,規(guī)劃器假定在涉及的列上的條件是兼容的并且因此是冗余的。如果它們是不兼容的,正確的估計將是零行,但是那種可能性不會被考慮。例如,給定一個這樣的查詢
SELECT * FROM zipcodes WHERE city = 'San Francisco' AND zip = '94105';
規(guī)劃器將會忽視city
子句,因為它不改變選擇度,這是正確的。不過,即便真地只有零行滿足下面的查詢,規(guī)劃器也會做出同樣的假設(shè)
SELECT * FROM zipcodes WHERE city = 'San Francisco' AND zip = '90210';
不過,函數(shù)依賴統(tǒng)計信息無法提供足夠的信息來排除這種情況。
在很多實際情況中,這種假設(shè)通常是能滿足的。例如,在應(yīng)用程序中可能有一個GUI僅允許選擇兼容的城市和郵編值用在查詢中。但是如果不是這樣,函數(shù)依賴可能就不是一個可行的選項。
單列統(tǒng)計信息存儲每一列中可區(qū)分值的數(shù)量。在組合多個列(例如GROUP BY a, b
)時,如果規(guī)劃器只有單列統(tǒng)計數(shù)據(jù),則對可區(qū)分值數(shù)量的估計常常會錯誤,導(dǎo)致選擇不好的計劃。
為了改進(jìn)這種估計,ANALYZE
可以為列組收集可區(qū)分值統(tǒng)計信息。和以前一樣,為每一種可能的列組合做這件事情是不切實際的,因此只會為一起出現(xiàn)在一個統(tǒng)計信息對象(用ndistinct
選項定義)中的列組收集數(shù)據(jù)。將會為列組中列出的列的每一種可能的組合都收集數(shù)據(jù)。
繼續(xù)之前的例子,ZIP代碼表中的可區(qū)分值計數(shù)可能像這樣:
CREATE STATISTICS stts2 (ndistinct) ON city, state, zip FROM zipcodes;
ANALYZE zipcodes;
SELECT stxkeys AS k, stxdndistinct AS nd
FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid)
WHERE stxname = 'stts2';
-[ RECORD 1 ]------------------------------------------------------?--
k | 1 2 5
nd | {"1, 2": 33178, "1, 5": 33178, "2, 5": 27435, "1, 2, 5": 33178}
(1 row)
這表示有三種列組合有33178個可區(qū)分值:ZIP代碼和州、ZIP代碼和城市、ZIP代碼+城市+周(事實上對于表中給定的一個唯一的ZIP代碼,它們本來就應(yīng)該是相等的)。另一方面,城市和州的組合只有27435個可區(qū)分值。
建議只對實際用于分組的列組合以及分組數(shù)錯誤估計導(dǎo)致了糟糕計劃的列組合創(chuàng)建ndistinct
統(tǒng)計信息對象。否則,ANALYZE
循環(huán)只會被浪費。
為每列存儲的另一種統(tǒng)計信息是頻繁值列表。 這樣可以對單個列進(jìn)行非常準(zhǔn)確的估計,但是對于在多個列上具有條件的查詢,可能會導(dǎo)致嚴(yán)重的錯誤估計。
為了改善這種估計,ANALYZE
可以收集列組合上的MCV列表。 與功能依賴和n-distinct系數(shù)類似,對每種可能的列分組進(jìn)行此操作都是不切實際的。 在這種情況下,甚至更是如此,因為MCV列表(與功能依賴性和n-distinct系數(shù)不同)存儲了公共列值。 因此,僅收集在使用mcv
選項定義的統(tǒng)計對象中同時出現(xiàn)的那些列組的數(shù)據(jù)。
繼續(xù)前面的示例,郵政編碼表的MCV列表可能類似于以下內(nèi)容(與更簡單的統(tǒng)計信息不同,它需要一個函數(shù)來檢查MCV內(nèi)容):
CREATE STATISTICS stts3 (mcv) ON city, state FROM zipcodes;
ANALYZE zipcodes;
SELECT m.* FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid),
pg_mcv_list_items(stxdmcv) m WHERE stxname = 'stts3';
index | values | nulls | frequency | base_frequency
-------+------------------------+-------+-----------+----------------
0 | {Washington, DC} | {f,f} | 0.003467 | 2.7e-05
1 | {Apo, AE} | {f,f} | 0.003067 | 1.9e-05
2 | {Houston, TX} | {f,f} | 0.002167 | 0.000133
3 | {El Paso, TX} | {f,f} | 0.002 | 0.000113
4 | {New York, NY} | {f,f} | 0.001967 | 0.000114
5 | {Atlanta, GA} | {f,f} | 0.001633 | 3.3e-05
6 | {Sacramento, CA} | {f,f} | 0.001433 | 7.8e-05
7 | {Miami, FL} | {f,f} | 0.0014 | 6e-05
8 | {Dallas, TX} | {f,f} | 0.001367 | 8.8e-05
9 | {Chicago, IL} | {f,f} | 0.001333 | 5.1e-05
...
(99 rows)
這表明城市和州的最常見組合是華盛頓特區(qū),實際頻率(在樣本中)約為0.35%。 組合的基本頻率(根據(jù)簡單的每列頻率計算)僅為0.0027%,導(dǎo)致兩個數(shù)量級的低估。
建議僅在實際在條件中一起使用的列的組合上創(chuàng)建MCV統(tǒng)計對象,對于這些組合,錯誤估計組數(shù)會導(dǎo)致糟糕的執(zhí)行計劃。 否則,只會浪費ANALYZE
和規(guī)劃時間。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: