1. 程式人生 > >節選翻譯 《Pro SQL Server Internals, 2nd edition》(P55-P58)

節選翻譯 《Pro SQL Server Internals, 2nd edition》(P55-P58)

升級 選擇執行 問題 表示 完成後 重復值 sp1 頁面 鏈接

本文選自《Pro SQL Server Internals》

作者: Dmitri Korotkevitch

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

第3章

統計

SQL Server查詢優化器在為查詢選擇執行計劃時使用基於成本的模型。它估計不同執行計劃的成本,並選擇成本最低的執行計劃。記得,但是,該SQL Server並不搜索可用於查詢的最佳執行計劃,而是評估所有可能的替代方案在CPU方面既耗時又昂貴。查詢優化器的目標是找到一個足夠好的執行計劃,足夠快。

基數估計(在每一步中需要處理的行數的估計查詢執行)是查詢優化的重要因素之一。這個數字影響選擇關於連接策略,查詢執行所需的內存量(內存授予)以及許多其他策略東西。


訪問數據時要使用的索引的選擇就是這些因素之一。你會記得的,鑰匙以及RID查找操作在I/O方面是昂貴的,並且SQL Server不使用非集群索引當它估計需要大量的這些操作時。SQL Server維護統計數據在索引上,在某些情況下在列上,這有助於執行這樣的估計。

SQL服務器統計信息簡介

統計信息簡介

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

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

技術分享圖片

如您所見,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所示。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ;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); -- Updating the statistics update statistics dbo.Books IDX_Books_ISBN with fullscan;

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

技術分享圖片

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

讓我們運行SELECT BookId,Title FROM dbo.Books WHERE ISBN LIKE‘114%‘語句並檢查執行計劃,如圖3-3所示。

技術分享圖片

統計和執行計劃

SQL Server默認自動創建和更新統計信息。 數據庫級別有兩個控制此類行為的選項:

1.“自動創建統計信息”控制優化程序是否自動創建列級統計信息。 此選項不會影響始終創建的索引級統計信息。默認情況下啟用“自動創建統計數據庫”選項。

2.啟用“自動更新統計數據庫”選項後,SQL Server會在每次編譯或執行查詢時檢查統計信息是否過時,並在需要時更新它們。 默認情況下也會啟用“自動更新統計數據庫”選項。

■ 提示:您可以使用STATISTICS_ NORECOMPUTE索引選項控制索引級別上統計信息的自動更新行為。 默認情況下,此選項設置為OFF,這意味著統計信息會自動更新。 在索引或表級別更改自動更新行為的另一種方法是使用sp_autostats系統存儲過程。

SQL Server根據執行的更改數量確定統計信息是否已過時影響統計信息列的INSERT,UPDATE,DELETE和MERGE語句。 SQL Server計算統計信息列的更改次數,而不是更改的行數。 例如,如果您將同一行更改100次,則將其計為100次更改而不是1次更改。

有三種不同的方案,稱為統計信息更新閾值,有時也稱為統計信息重新編譯閾值,其中SQL Server將統計信息標記為過時。

1 .當表為空時,SQL Server在向表中添加數據時會過時。

2. 當表的行少於500行時,SQL Server會在統計列每500次更改後過期統計信息。

3. 在SQL Server 2016和SQL Server 2016之前,數據庫兼容級別<130:當一個表有500行或更多行時,SQL Server會在每500+(表中總行數的20%)變化後過期統計信息統計列。在SQL Server 2016中,數據庫兼容級別為130:大型表上的統計信息更新閾值將變為動態,並取決於表的大小。 表具有的行越多,閾值越低。 在具有數百萬甚至數十億 行的大型表上,統計信息更新閾值可能只是表中總行數的一小部分。 SQL Server 2008R2 SP1及更高版本中的跟蹤標誌T2371也可以啟用此行為。

技術分享圖片

這導致我們得出一個非常重要的結論。使用靜態統計信息更新閾值,觸發統計信息更新所需的統計信息列的更改次數與表大小成比例。表越大,統計信息自動更新的次數就越少。例如,對於包含10億行的表,您需要對統計信息列執行大約2億次更改,以使統計信息過期。建議盡可能使用動態更新閾值。

讓我們來看看這種行為如何影響我們的系統和執行計劃。此時,表dbo。書籍有1,265,000行。讓我們在表中添加250,000行,前綴為999,如清單3-5所示。在此示例中,我使用的是未啟用T2371的SQL Server 2012。如果在啟用動態統計信息更新閾值的情況下運行它,則可以看到不同的結果。此外,SQL Server 2014中引入的新基數估計器也可以改變行為。我們將在本章後面討論它。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ;with Postfix(Postfix) as ( select 100000001 union all select Postfix + 1 from Postfix where Postfix < 100250000 ) insert into dbo.Books(ISBN, Title) select ‘999-0‘ + convert(char(9),Postfix) ,‘Title for ISBN 999-0‘ + convert(char(9),Postfix) from Postfix option (maxrecursion 0);

現在,讓我們運行SELECT * FROM dbo.Books WHERE ISBN LIKE‘999%‘查詢,選擇具有這種前綴的所有行。

如果檢查查詢的執行計劃(如圖3-7所示),您將看到非聚簇索引查找和鍵查找操作,即使它們在您需要從表中選擇近20%的行時效率低下。

技術分享圖片

您還將在圖3-7中註意到,Index Seek運算符的估計行數和實際行數之間存在巨大差異。 SQL Server估計表中只有31.4行,前綴為999,即使有250,000行具有這樣的前綴。 結果,產生了非常低效的計劃。

讓我們通過運行DBCC SHOW_STATISTICS(‘dbo.Books‘,IDX_ BOOKS_ISBN)命令來查看IDX_BOOKS_ISBN統計信息。 輸出如圖3-8所示。 正如您所看到的,即使我們在表中插入了250,000行,統計信息也沒有更新,並且直方圖中沒有前綴999的數據。第一個結果集中的行數對應於行中的行數。 上次統計信息更新期間的表。 它不包括剛剛插入的250,000行。

技術分享圖片

現在讓我們使用UPDATE STATISTICS dbo.Books IDX_Books_ISBN WITH FULLSCAN命令更新統計信息,然後再次運行SELECT * FROM dbo.Books WHERE ISBN LIKE‘990%‘查詢。 查詢的執行計劃如圖3-9所示。 估計的行數現在是正確的,並且SQL Server最終得到了一個更有效的執行計劃,該計劃使用聚簇索引掃描,I / O讀取比以前少了大約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所示。

?
1 2 3 4 5 6 7 8 9 10 11 12 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值重建統計信息。

技術分享圖片

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

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

節選翻譯 《Pro SQL Server Internals, 2nd edition》(P55-P58)