性能調優:理解Set Statistics IO輸出


性能調優是DBA的重要工作之一。很多人會帶着各種性能上的問題來問我們。我們需要通過SQL Server知識來處理這些問題。經常被問到的一個問題是:早上這個存儲過程運行時間還是可以的,但到了晚上就很慢很慢。對此,我們可以笑着回答:這個存儲過程運行多次后,已經累趴了,所以很慢。

存儲過程或語句運行時間取決於服務器的工作量。如果在晚上,服務器負擔很重的話,你的存儲過程可能需要更多的時間來運行,因為它在等待CPU周期(CPU cycle)和IO完成(IO completion)。為了獲得一致的響應時間,我們需要減少執行完成的資源需求,那就是所謂的性能調優。

IO和CPU是完成執行的主要資源使用對象。更少的資源使用,更穩定的性能表現。這篇文章我們來理解下性能調優中DBCC STATISTCS IO所扮演的角色。

默認情況下SET STATISTCS IO是停用的,我們可以通過下列語句在當前會話級別打開。

1 SET STATISTICS IO  ON

這個語句可以幫助我們獲得在語句執行時,所發生IO數(頁讀/寫)。我們來看一個例子的輸出。

 1 USE StatisticsDB
 2 GO
 3 SELECT * INTO SalesOrderDetail FROM AdventureWorks2008R2.Sales.SalesOrderDetail 
 4 GO
 5 SET STATISTICS IO ON
 6 DBCC dropcleanbuffers
 7 DBCC freeproccache
 8 GO
 9 SELECT * FROM SalesOrderDetail 
10 GO
11 SELECT * FROM SalesOrderDetail 

 

Set Statistics IO的輸出信息可以在消息TAB頁里找到。同樣的語句我們執行了2次,第一次是在清空緩存后執行,第2次沒有。

我們來看下輸出信息:

掃描計數(Scan count):

根據微軟在線幫助,掃描計數是在任何方向都達到葉級別后啟動的查詢/掃描數,目的在於檢索用於構造輸出的最終數據集的所有值。

  • 如果使用的索引是主鍵的唯一索引或聚集索引並且您僅查找一個值,則掃描計數為 0。 例如 WHERE Primary_Key_Column = <value>。
  • 當您使用對非主鍵列定義的非唯一的聚集索引搜索一個值時,掃描計數為 1。 這是為了針對您正在搜索的鍵值檢查重復值。 例如 WHERE Clustered_Index_Key_Column = <value>。

  • 當 N 為通過使用索引鍵定位鍵值后,在葉級別的左側或右側啟動的不同查找/掃描數時,則掃描計數為 N。

這個數字告訴我們優化器所選擇的計划,對這個對象的重復讀取次數。很多人誤以為這個是對整張表的讀取次數,這是完全錯誤的。

我們通過一個例子來理解掃描計數。

 1 CREATE TABLE ScanCount (Id INT IDENTITY(1,1),Value CHAR(1))
 2 INSERT INTO ScanCount (Value ) VALUES ('A') ,('B'),('C'),('D'), ('E') , ('F') 
 3 CREATE UNIQUE CLUSTERED INDEX ix_ScanCount ON ScanCount(Id)
 4 
 5 SET STATISTICS IO ON
 6 --Unique clustered Index used to search single value
 7 SELECT * FROM ScanCount  WHERE Id =1
 8 --Unique clustered Index used to search multiple value
 9 SELECT * FROM ScanCount  WHERE Id IN(1,2,3,4,5,6)
10 --Unique clustered Index used to search multiple value
11 SELECT * FROM ScanCount  WHERE Id BETWEEN 1 AND 6

我們來看下上面3個查詢語句的輸出。

在第1個SELECT語句的輸出里,掃描計數為0。這和MSDN里在線幫助“如果使用的索引是主鍵的唯一索引或聚集索引並且您僅查找一個值,則掃描計數為 0。”描述一致。因為它是唯一索引(聚集/非聚集索引),不需要在葉子層,進行進一步的向左或向右掃描,因為這里只有一個值來匹配。那也是在唯一索引上查找單一值,掃描計數為0的原因。掃描計數是1的話,會在非唯一索引(聚集或非聚集索引)上發生。

對於第2個SELECT語句,掃描計數是6.這是因為我們在找多個不同值。MSDN在線幫助對此有詳細說明: “如果使用的索引是主鍵的唯一索引或非聚集索引,你在查找N個值,則掃描計數為N。”。

我們來看看執行計划里的SEEK謂語,將更清晰:

即使只有一個where條件,還是會分裂成多個謂語。對於每個SEEK謂語,它會生成1個掃描數。

對於最后一個SELECT語句,掃描計數為1,因為MSDN在線幫助說了: “當 N 為通過使用索引鍵定位鍵值后,在葉級別的左側或右側啟動的不同查找/掃描數時,則掃描計數為 N。” 在葉子節點聚集索引結構用來找到1值后,葉子層的向左掃描開始,直到找到值6。我們看下執行計划里的SEEK 謂語,將更清晰:

邏輯讀取(logical Read):

從數據緩存讀取的頁數。數字越小,性能越好。在性能調優中這個數字非常重要。因為它不會隨着執行又執行而改變,除非數據或查詢語句有變動。在進行性能調優時,這個可以作為性能提升的重要參考。

物理讀取(physical reads):

從磁盤讀取的頁數。這個會隨着執行又執行而改變。大多數情況下,連續第2次的執行時,它的物理讀取值為0(可以參考上面連續查詢的物理讀取數變化)。

如果連續執行后,物理讀取次數下降了,我們可以假定是服務器上內存使用配置的錯誤,或者服務器工作量飽和,有內存壓力。你需要在服務器級別思考問題的原因。在查詢調優時,這個數字不太重要,因為它一直在變,對於下降這個值,你不能對它做出太多控制。

預讀 (read-ahead reads):

為進行查詢而放入緩存的頁數。這個值告訴我們物理頁讀取數,即SQL Server執行的,作為預讀機制的一部分。在查詢執行請求那些可能用到頁之前,SQL Server把物理數據頁讀入緩存,用於完成接下來查詢的頁需要。

可以看到,物理讀取是2次,預讀是946次。這就是說,查詢執行請求了2個頁,並預讀了946個頁到數據緩存,SQL Server估計下次查詢可能要用到這些頁。和物理讀取一樣,這個值對在查詢調優里並不重要。

lob 邏輯讀取(lob logical reads):

從數據緩存讀取的 text、ntext、image 或大值類型 (varchar(max)、nvarchar(max)、varbinary(max)) 頁的數目。這個和邏輯讀一樣重要,我們要非常重視。

lob 物理讀取(lob physical reads):

從磁盤讀取的 text、ntext、image 或大值類型頁的數目。

lob 預讀(lob read-ahead reads):

為進行查詢而放入緩存的 text、ntext、image 或大值類型頁的數目。

總結下,邏輯讀取和LOB邏輯讀取是2個重要數值,在性能調優時,我們要重點圍觀。如果把這2個值調低,不在本文的討論范圍。通常創建合適的索引或重寫查詢可以幫助我們徹底降低這2個值。

參考文章:

http://www.sqlservercentral.com/blogs/practicalsqldba/2013/07/16/sql-server-performance-tuning-understanding-dbcc-statistics-io-output/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM