在日常生活中,我們用統(tǒng)計信息來采取決定。SQL Server優(yōu)化器也用同樣的方式,使用統(tǒng)計信息來選擇正確的執(zhí)行計劃。如果統(tǒng)計信息錯誤或過期,SQL Server可能就會選擇錯誤的執(zhí)行計劃。在這個文章里,我們換個方式理解下統(tǒng)計信息。
查詢優(yōu)化器使用統(tǒng)計信息來判斷每一步返回的行。執(zhí)行計劃里的估計行數(shù)信息是基于列的可用統(tǒng)計信息計算而來的。統(tǒng)計信息給我們列里數(shù)據(jù)分布情況。沒有統(tǒng)計信息,查詢優(yōu)化器不能夠判斷不同計劃的效率。通過使用統(tǒng)計信息,查詢優(yōu)化器在訪問數(shù)據(jù)時可以做出正確的選擇。
在我們定義索引時,統(tǒng)計信息會自動創(chuàng)建。除此之外,當(dāng)列在查詢里被引用,作為WHERE條件的一部分,在group by子句里或join條件里,統(tǒng)計信息都會創(chuàng)建。為了自動創(chuàng)建統(tǒng)計信息,在數(shù)據(jù)庫層里的AUTO_CREATE_STATISTICS設(shè)置應(yīng)該被啟用。默認(rèn)情況下這個設(shè)置是被啟用的。除此之外,統(tǒng)計信息可以使用CREATE STATISTICS命令創(chuàng)建。
在SQL Server里存儲的統(tǒng)計數(shù)字是關(guān)于密度向量和直方圖(數(shù)據(jù)分布)的信息。在我們討論更多細(xì)節(jié)前,先理解這2個概念。
密度向量:在給出列或一組列唯一值的比例。統(tǒng)計密度向量的公式:1/列(或一組列)不同值個數(shù)。
密度向量用來衡量列的唯一性或列的選擇性。密度向量的值在0和1之間。如果這列的密度值為1,表示這列的所有記錄值一樣,選擇性低。更高的密度帶來更低的選擇性。如果這列的密度值為0.003,表示這列有1/0.003=333個不同值。
我們來看個例子,用下列語句創(chuàng)建表并在上面建立2個索引。
1 USE StatisticsDB2 GO3 4 SELECT * INTO SalesOrderDetail FROM AdventureWorks2008R2.Sales.SalesOrderDetail5 CREATE UNIQUE CLUSTERED INDEX ix_SalesOrderDetailID ON SalesOrderDetail(SalesOrderDetailID)6 CREATE NONCLUSTERED INDEX ix_PRoductid ON SalesOrderDetail(productid)
我們來看看這2個索引的統(tǒng)計信息。
1 DBCC SHOW_STATISTICS('dbo.SalesOrderDetail', 'ix_SalesOrderDetailID')
輸出結(jié)果有3個表,分別是:統(tǒng)計信息頭,密度向量和直方圖。
在第1部分(統(tǒng)計信息頭)
可以使用DBCC SHOW_STATISTICS加WITH STAT_HEADER來只獲取統(tǒng)計頭信息。
在第2部分的密度表,我們只看到一條記錄,因為在我們索引里只有1列。
所有密度列給我們SalesOrderDetailsId列的密度值(1/列(或一組列)不同值個數(shù))。所有密度列給我們值 8.242868E-06 =0.000008242868。這表示SalesOrderDetailsId列有 1/0.000008242868=121317個唯一值,我們可以用下列語句驗證下。
1 SELECT COUNT(DISTINCT SalesOrderDetailID ) FROM SalesOrderDetail
可以使用DBCC SHOW_STATISTICS加WITH DENSITY_VECTOR來只獲取密度向量信息。
我們來看看非聚集索引ix_productid的密度。
1 DBCC SHOW_STATISTICS('dbo.SalesOrderDetail', 'ix_productid') WITH DENSITY_VECTOR
在密度表里可以看到2行記錄,即使我們的非聚集索引是在單列上。這是因為聚集鍵是非聚集索引的一部分(參見索引深入淺出(4/10):非聚集索引的B樹結(jié)構(gòu)在聚集表)。
第一行告訴我們,ProductID列的密度向量值為0.003759399,換句話說,在ProductID列有1/0.003759399=226個唯一值。我們可以驗證下。
1 SELECT COUNT(DISTINCT ProductID) FROM dbo.SalesOrderDetail
第二行告訴我們,ProductID和SalesOrderDetailID組合列的密度向量值是0.000008242868,換句話說,ProductID和SalesOrderDetailID組合列有121317個唯一值,這個和表的總記錄數(shù)是一致的。
密度向量值會用在哪里呢,我們看下下面查詢的執(zhí)行計劃,點擊工具欄的顯示包含實際的執(zhí)行計劃。
1 SELECT ProductID,COUNT(*) FROM dbo.SalesOrderDetail GROUP BY ProductID
在執(zhí)行計劃里,在流聚合運算符的輸出里,我們看到估計行數(shù)是266。在ProductID列唯一值(個數(shù))可以從密度表里拿到。但我們怎么證明查詢優(yōu)化器是用這個值來計算估計行數(shù)。我們創(chuàng)建另外一個沒有任何索引的SalesOrderDetail表。
1 SELECT * INTO SalesOrderDetail_NoStats FROM SalesOrderDetail
通過下面語句我們可以看出,這表沒有任何的統(tǒng)計信息。
1 EXEC SP_HELPSTATS 'SalesOrderDetail_NoStats', 'ALL'
我們再看下這個表的剛才查詢,點擊工具欄的顯示包含實際的執(zhí)行計劃:
1 SELECT ProductID,COUNT(*) FROM dbo.SalesOrderDetail_NoStats GROUP BY ProductID
在沒有任何統(tǒng)計索引和統(tǒng)計信息的情況下,優(yōu)化器再一次在流聚合運算符的輸出里估計行數(shù)是266。我們再次檢查下這個表的統(tǒng)計信息。
1 EXEC SP_HELPSTATS 'SalesOrderDetail_NoStats', 'ALL'
是的,在估計執(zhí)行計劃是,SQL Server在productID列創(chuàng)建了統(tǒng)計信息來幫助優(yōu)化器選擇正確的執(zhí)行計劃。我們來看看這個統(tǒng)計信息的詳情。
1 DBCC SHOW_STATISTICS('dbo.SalesOrderDetail_NoStats', '_WA_Sys_00000005_7E6CC920')
在統(tǒng)計信息頭,我們注意到Rows Sampled值比Rows值小。這是因為在自動創(chuàng)建統(tǒng)計信息時,SQL Server沒有掃描整個表,只掃描了表的樣本。為什么會這樣在接下來的文章里會談到。簡而言之,在非聚集索引字段里,統(tǒng)計信息幫助優(yōu)化器在每一步操作時判斷估計行數(shù),什么樣的連接是合適的,還有在計劃中的執(zhí)行順序。
新聞熱點
疑難解答
圖片精選