1. 程式人生 > >翻譯之:SQL Server統計信息簡介

翻譯之:SQL Server統計信息簡介

有時 微軟 時間 異步更新 rst mas 常見 針對 但是

本文選自《Pro SQL Server Internals》

作者: Dmitri Korotkevitch

出版社: Apress

出版年: 2016-12-29

頁數: 804

作者簡介:Dmitri Korotkevitchis是微軟SQL Server MVP和微軟認證大師。作為應用程序和數據庫開發人員、數據庫管理員和數據庫架構師,他具有多年使用SQL Server的經驗。他專門從事OLTP系統在高負載下的設計、開發和性能調優。Dmitri經常在各種Microsoft和SQL PASS活動上發言,他為世界各地的客戶提供SQL Server培訓。

原文鏈接:http://www.doc88.com/p-4042504089228.html

SQL Server統計信息簡介

SQL Server統計信息是系統對象,其中包含有關索引鍵值中的數據分布的信息,有時還包含常規列值。 可以在支持比較操作的任何數據類型上創建統計信息,例如>,<,=等。

讓我們從上一章清單2-15中創建的dbo.Books表中檢查IDX_BOOKS_ISBN索引統計信息。您可以使用DBCC SHOW_STATISTICS(‘dbo.Books‘,IDX_BOOKS_ISBN)命令來完成此操作。 結果如圖3-1所示。

技術分享圖片

圖3-1 DBCC SHOW_STATISTICS輸出

如您所見,DBCC SHOW_STATISTICS命令返回三個結果集。第一個包含有關統計信息的常規元數據信息,例如名稱,更新日期,更新統計信息時索引中的行數等。第一個結果集中的“步驟”列指示直方圖中的步數/值的數量(稍後將詳細介紹)。“查詢優化程序”不使用“密度”值,僅出於向後兼容性目的而顯示。

第二個結果集稱為密度向量,它包含有關統計(索引)中鍵值組合的密度的信息。它是基於1 /不同值的數量計算得出的,它表示平均每個鍵值組合有多少行。盡管IDX_Books_ISBN索引只定義了一個鍵列ISBN,但它還包含一個聚簇索引鍵作為索引行的一部分。我們的表有1,252,500個唯一的ISBN值,ISBN列的密度為1.0 / 1,252,500 = 7.984032E-07。 (ISBN,BookId)列的所有組合也是唯一的並且具有相同的密度。

最後的結果集稱為直方圖。直方圖中的每個記錄(稱為直方圖步驟)都包括統計信息(索引)最左列中的樣本鍵值以及有關從前一個值到當前RANGE_HI_KEY值的值範圍內的數據分布的信息。讓我們更深入地檢查直方圖列。

RANGE_HI_KEY列存儲密鑰的樣本值。 此值是直方圖步驟定義的範圍的上限鍵值。 例如,圖3-1中直方圖中的記錄(步驟)#3與RANGE_HI_KEY =‘104-0100002488‘存儲有關從ISBN>‘101-0100001796‘到ISBN <=‘104-0100002488‘的間隔的信息。

RANGE_ROWS列估計間隔內的行數。 在我們的例子中,記錄(步驟)#3定義的間隔有8,191行。

EQ_ROWS表示有多少行的鍵值等於RANGE_HI_KEY上限值。 在我們的例子中,只有一行ISBN =‘104-0100002488‘。

DISTINCT_RANGE_ROWS表示密鑰的不同值。在這段時間內。在我們的示例中,鍵的所有值都是唯一的,因此DISTINCT_RANGE_ROWS = RANGE_ROWS。AVG_RANGE_ROWS表示每個不同鍵的平均行數區間中的值。在我們的例子中,鍵的所有值都是唯一的,所以AVG_RANGE_ROWS = 1。讓我們在索引中插入一組重復的ISBN值,代碼如清單3-1所示。

清單3-1 將重復的ISBN值插入索引中。

;with Prefix(Prefix)

as ( select Num from (values(104),(104),(104),(104),(104)) Num(Num) )

,Postfix(Postfix)

as

(

select 100000001

union all

select Postfix + 1 from Postfix where Postfix < 100002500

)

insert into dbo.Books(ISBN, Title)

select

convert(char(3), Prefix) + ‘-0‘ + convert(char(9),Postfix)

,‘Title for ISBN‘ + convert(char(3), Prefix) + ‘-0‘ + convert(char(9),Postfix)

from Prefix cross join Postfix

option (maxrecursion 0);

——更新統計數據

更新統計dbo.Books IDX_Books_ISBN與全掃描;

現在,如果再次運行DBCC SHOW_STATISTICS(‘dbo.Books‘,IDX_BOOKS_ISBN)命令,您將看到如圖3-2所示的結果。

技術分享圖片

圖3-2 DBCC SHOW_STATISTICS輸出

具有前綴104的ISBN值現在具有重復項,這會影響直方圖。 還值得一提的是,第二個結果集中的密度信息也發生了變化。具有重復值的ISBN s的密度高於(ISBN,BookId)列的組合,這仍然是唯一的。

讓我們運行SELECT BOOKID,標題FROM dbo.Books WHERE ISBN LIKE“114%”語句,並檢查執行計劃,如圖3-3所示。

技術分享圖片

圖3-3 查詢的執行計劃

大多數執行計劃操作員都有兩個重要的屬性。 實際行數表示在執行者執行期間處理了多少行。 估計行數表示SQL Server在查詢優化階段為該運算符估計的行數。 在我們的例子中,SQL Server估計有2,625行,其中ISBN以114開頭。如果您查看圖3-2中所示的直方圖,您將看到步驟10存儲有關ISBN間隔的數據分布的信息,包括 您正在選擇的值。 即使使用線性近似,您也可以估計接近SQL Server確定的行數。

關於統計數據,有兩件非常重要的事情需要記住。

1.直方圖僅存儲有關最左側統計(索引)列的數據分布的信息。 有關統計中關鍵值的多列密度的信息,但就是直方圖中的所有其他信息僅與最左邊的統計列的數據分布有關。

2.無論表的大小和表是否已分區,SQL Server在直方圖中最多保留200個步驟。 每個直方圖步驟所覆蓋的間隔隨著表的增長而增加。 這導致在大表格的情況下不太準確的統計數據。

對於復合索引,當索引中的所有列都用作所有查詢中的謂詞時,將具有較低密度/較高百分比的唯一值的列定義為索引的最左列是有益的。 這將允許SQL Server更好地利用統計信息中的數據分布信息。 但是,您應該考慮謂詞的SARGability。 例如,如果所有查詢都在where子句中使用FirstName = @ FirstName和LastName = @ LastName謂詞,則最好將LastName作為索引中最左側的列。 盡管如此,對於FirstName = @ FirstName和LastName <> @ LastName之類的謂詞不是這種情況,其中LastName不是SARGable。

統計和執行計劃

sql服務器默認自動創建和更新統計數據。數據庫中有兩個選項控制此類行為的級別:

1、自動創建統計控制是否優化程序自動創建列級統計。這個選項不會產生影響,因為索引級統計始終會創建。默認情況下會啟用自動創建統計數據庫選項。

2、啟用自動更新統計數據庫選項時,sql服務器每次編譯或執行查詢時都會檢查統計數據是否過時,並在需要時更新統計數據。默認情況下也會啟用自動更新統計數據庫選項。

提示:您可以通過使用統計計算(STATISTICS_NORECOMPUTE)索引選項來控制索引級別上的統計數據的自動更新行為。默認情況下,此選項將被關閉,意思就是說統計數據默認自動更新。在索引或表級別上改變自動更新行為的另一種方法是使用sp_autostats系統存儲過程。

sql服務器根據插入、更新、刪除和合並語句執行的影響統計列的更改次數確定統計是否過時。sql服務器計算統計列被更改的次數,而不是更改行的數目。例如,如果您將同一行更改100次,它將被算作100次更改,而不是1次更改。

有三種不同的方案,稱為統計更新閾值,有時也稱為統計重新編譯閾值,其中sql服務器將統計標記為過時。

1、當表為空時,當您將數據添加到表中時,sql服務器將超出統計數據。

2、當表的行少於500行時,每500次統計列的更改,sql服務器就會超出統計數據。

3、2016版sql服務器和之前的版本,具有數據庫兼容性級別小於130.如果表中有500行或更多行,則在統計列每500+(占表中行總數的20%)發生變化後,sql服務器就會超出統計數據。

4、2016版sql服務器數據庫兼容性級別等於130.大量表的統計數據更新閾值變成動態,而且取決於表的大小。表的行越多,閾值越低。在上百萬行甚至數十億行的大量表格中,統計更新閾值只能是表中行總數百分比的一小部分。此特征也可以在sql服務器2008R2 SP1及更高版本中啟用跟蹤標誌T2371

技術分享圖片

表3-1總結了不同版本的sql服務器的統計更新閾值行為。

這使我們得出一個非常重要的結論。

使用靜態統計更新閾值,觸發統計更新所需的統計列的更改數與表大小成正比。表格越大,自動更新的統計數據就越少。例如,在有10億行的表的情況下,您需要對統計列執行約2億項更改使統計數據過時。如果可以的話建議使用動態更新閾值。

讓我們看看這種行為是如何影響我們的系統和執行計劃的。在這一點上,該表dbo.Books有1265000行。我們把250,000行加上前綴999,如表3-5.在此示例中,我使用的是sql服務器2012,未啟用T2371。如果啟用動態統計更新閾值就可以看到不同的結果。此外,在sql服務器2014中引入的新的基數估計器也可以改變行為。我們會在後面章節中進行討論。

我們執行SELECT * FROM dbo.Books WHERE ISBN LIKE ‘999%‘ 語句,它可以選擇帶有此前綴的所有行。

技術分享圖片

如果檢查查詢的執行計劃,如圖3-7所示,您將看到非集群索引查找和鍵查找操作。

您還會在圖3-7中註意到索引查找運算符的估計行數和實際行數之間存在巨大差異。sql服務器估計表中只有31.4行帶有前綴999,實際有25萬行帶有這樣的前綴。這就產生了一個非常低效的計劃。

技術分享圖片

接下來,通過DBCC執行命令 SHOW_STATISTICS (‘dbo.Books‘, IDX_BOOKS_ISBN) 看看 IDX_BOOKS_ISBN統計。輸出如圖3-8所示。如您所見,即使我們在表格中插入了25萬行,統計數據也沒有更新,而且直方圖中沒有關於999前綴的數據。第一個結果集中的行數相對應上一個統計期間表中的行數更新。它不包括剛剛插入的250,000行。

通過語句UPDATE STATISTICS dbo.Books IDX_Books_ISBN WITH FULLSCAN更新統計,然後重新執行 SELECT * FROM dbo.Books WHERE ISBN LIKE ‘999%‘ 語句。執行計劃如3-9.現在估計的行數是正確的,而sql服務器最終采用了更高效的執行計劃,使用的是集群索引掃描,比以前減少了大約17倍的輸入/輸出讀取量。

技術分享圖片

如你所見,不正確的基數估計會導致執行計劃效率低下。過時的統計數據也會是造成基數估計錯誤的最常見原因之一。您可以通過檢查執行計劃中的估計行和實際行數來確定其中的一些情況。這兩個數值之間的巨大差異往往表明統計數字不正確。更新統計可以解決這個問題,產生更有效率的執行計劃。

統計維護

正如我已經提到的,SQL Server默認自動更新統計信息。對於小表,這種行為通常是可以接受的;但是,對於具有數百萬或數十億行的大型表,您不應該依賴自動統計信息更新,除非您使用的SQL Server 2016的數據庫兼容級別為130或啟用了跟蹤標誌T2371。按20%統計信息更新閾值觸發統計信息更新所需的更改次數將非常高,因此,不會經常觸發更新。

在這種情況下,建議您手動更新統計信息。在選擇最佳統計維護策略時,您必須分析表的大小,數據修改模式和系統可用性。例如,如果系統在工作時間之外沒有負載,您可以決定每晚更新關鍵表的統計信息。不要忘記統計信息和/或索引維護會為SQL Server增加額外的負載。 您必須分析它如何影響同一服務器和/或磁盤陣列上的其他數據庫。

設計統計維護策略時需要考慮的另一個重要因素是如何修改數據。對於具有不斷增加或減少的鍵值的索引,您需要更頻繁地更新統計信息,例如當索引中最左側的列定義為標識或使用序列對象填充時。如您所見,如果特定鍵值超出直方圖,SQL Server會大大低估行數。 在SQL Server 2014到2016中,此行為可能會有所不同,我們將在本章後面部分中看到。

您可以使用UPDATE STATISTICS命令更新統計信息。 當SQL Server更新統計信息時,它會讀取數據樣本而不是掃描整個索引。 您可以使用FULLSCAN選項更改該行為,該選項強制SQL Server讀取和分析索引中的所有數據。 正如您可能猜到的那樣,該選項提供了最準確的結果,盡管它可能會引入大量的I / O活動大表的情況。

提示重建索引時,SQL Server會更新統計信息。 我們將在第6章“索引碎片化”中更詳細地討論索引維護。

您可以使用sp_updatestats系統存儲過程更新數據庫中的所有統計信息。 建議您使用此存儲過程並在將其升級到新版本的SQL Server後更新數據庫中的所有統計信息。 您應該與DBCC UPDATEUSAGE存儲過程一起運行它,它會更正目錄視圖中不正確的頁面和行計數信息。

有一個sys.dm_db_stats_properties DMV,它顯示自上次統計信息更新以來對統計信息列所做的修改次數。 利用該DMV的代碼如清單3-9所示。

清單3-9 使用sys.dm_db_stats_properties

select

s.stats_id as [Stat ID], sc.name + ‘.‘ + t.name as [Table], s.name as [Statistics] ,p.last_updated, p.rows, p.rows_sampled, p.modification_counter as [Mod Count]

from sys.stats s join sys.tables t on s.object_id = t.object_id join sys.schemas sc on

t.schema_id = sc.schema_id outer apply sys.dm_db_stats_properties(t.object_id,s.stats_id) p

where

sc.name = ‘dbo‘ and t.name = ‘Books‘;

查詢結果如圖3-11所示,表明自上次統計信息更新以來,對統計信息列進行了250,000次修改。 您可以構建統計信息維護例程,定期檢查sys.dm_db_stats_properties DMV並使用較大的modification_counter值重建統計信息。

技術分享圖片

圖3-11 Sys.dm_db_stats_properties outp

另一個與統計相關的數據庫選項是異步自動更新統計信息。 默認情況下,當SQL Server檢測到統計信息已過時時,它會暫停查詢執行,同步更新統計信息,並在統計信息更新完成後生成新的執行計劃。 通過異步統計信息更新,SQL Server使用舊的執行計劃執行查詢,該計劃基於過時的統計信息,同時異步更新後臺統計信息。 建議您繼續使用同步統計信息更新除非系統具有非常短的查詢超時,在這種情況下,同步統計信息更新可以使查詢超時。

最後,SQL Server不會在您創建新索引時自動刪除列級統計信息。您應該手動刪除冗余的列級統計信息對象。

新基數估算器(SQL Server 2014-2016)

如您所知,查詢優化的質量取決於準確的基數。SQL Server必須正確估計查詢執行的每個步驟中的行數,以便生成有效的執行計劃。最初使用SQL Server 2005-2012中使用的基數估算模型為SQL Server 7.0開發並於1998年發布。顯然,在較新版本的SQL Server中有一些小的改進和更改; 然而,從概念上講,模型保持不變。

模型中使用了四個主要假設,包括:

均勻性:該模型假設在沒有統計信息的情況下統一數據分布。例如,在直方圖內部步驟中,假設所有鍵值均勻且均勻地分布。

獨立性:此模型假設實體中的屬性彼此獨立。例如,當查詢針對同一個表的不同列有多個謂詞時,它會假定列不以任何方式相關。

簡單包含:此模型假定用戶查詢表中存在的數據。例如,當您連接兩個表時,如果沒有統計信息,模型會假定一個表中的所有不同值都存在於另一個表中。此模型中連接運算符的選擇性基於連接謂詞的選擇性。

包含:此模型假定當將屬性與常量進行比較時,始終存在匹配。

翻譯之:SQL Server統計信息簡介