利用SQL Profiler處理開銷較大的查詢


  當SQL Server的性能變差時,最可能發生的是以下兩件事:

  • 首先,某些查詢產生了系統資源上很大的壓力。這些查詢影響整個系統的性能,因為服務器無法足夠快速地服務其他SQL查詢。
  • 另外,開銷較大的查詢阻塞了其他請求相同數據庫資源的查詢,進一步降低了這些查詢的性能。優化開銷較大的查詢不僅改進它們本身的性能,而且減少數據庫阻塞和SQL Server資源壓力從而提高了其他查詢的性能。

識別開銷較大的查詢

  SQL Server的目標是在最短時間內將結果集返回給用戶。為此,SQL Server查詢優化器生成一個成本效益高的查詢執行計划。查詢優化器計算許多因素的權重,包括執行查詢所需要的CPU、內存以及磁盤I/O的使用情況-這些均來自於由索引維護或過程中生成的統計。通常開銷最低的計划有最少的I/O,因為I/O操作代價昂貴。

  邏輯讀提供指出了查詢產生的內存壓力。它還提供了磁盤壓力指標,因為內存頁面必須在操作查詢中被備份,在第一次數據訪問期間寫入,並且在內存瓶頸時被移到磁盤上。查詢的邏輯讀數量越大,磁盤壓力的可能性就越大。過多的邏輯頁面也增加了CPU用於管理這些頁面的負載。

  導致大量邏輯讀的查詢通常在相應的大數據集上得到鎖。即使讀也需要在所有數據上的共享鎖。這些查詢阻塞了其他請求修改這些數據的查詢,但是不阻塞讀取數據的查詢。因為這些查詢固有的開銷並且需要長時間執行,他們持續地阻塞其他查詢。被阻塞的查詢進一步阻塞查詢,引入了數據中的阻塞鏈。

  識別開銷較大的查詢並優化它們有如下意義:

  •   增進開銷較大的查詢本身的性能;
  •   降低系統資源上的總體壓力;
  •   較少數據庫阻塞;

  其中開銷較大的查詢可以被分為如下兩類:

  •   單詞執行:查詢的一次單獨執行開銷較大;
  •   多次執行:查詢本身開銷並不大,但是該查詢的重復執行導致系統資源上的壓力;

  1、單次執行開銷較大的查詢

  可以分析SQL Profiler跟蹤輸出文件來識別開銷較大的查詢。比如,如果對識別執行大量的邏輯讀的查詢感興趣,應該在跟蹤輸出的Reads數據列上排序。

  •   捕捉表示典型工作負載的Profiler跟蹤;
  •   將跟蹤輸出保存到一個跟蹤文件;
  •   打開跟蹤文件進行分析;
  •   通過事件選擇選項卡,單擊組織列按鈕,在Reads列上分組跟蹤輸出。

  

  跟蹤輸出如下:

  

  在某些情況下,可能從系統監視器輸出中識別CPU上的大壓力。CPU上的壓力可能是因為大量CPU密集型操作,如存儲過程重編譯、總計函數、數據排序、哈希連接等。在這種情況下,應該在CPU列上排序Profiler跟蹤輸出以識別使用大量處理器周期的查詢。

  2、多次執行開銷較大的查詢

  有時候一個查詢可能本身開銷並不大,但是同一查詢多次執行的累積效應可能造成系統資源的壓力。在Reads列上排序對識別這種類型的查詢沒有幫助。如果希望知道查詢的多次執行進行的總讀取數,不幸的是Profiler在這里不能直接提供幫助,但是仍然可以用以下方法得到這一信息。

  •   在Profiler中跟蹤輸出的以下列上分組:EventClass、TextData和Reads。對於相同EventClass和TextData的分組,手工計算所有對應的Reads的總和。
  •   在Profiler中選擇文件=》另存為=》跟蹤表將輸出到一個跟蹤表。也可以使用內建函數fn_trace_gettable和Profiler的跟蹤文件輸出導入到一個跟蹤表。
  •   訪問sys.dm_exec_query_stats DMV從生產服務器上檢索信息。這假設打算處理一個即時的問題並且不關注歷史問題。

  在將跟蹤輸入保存到文件以后,先將跟蹤數據導入到一張表:

SELECT * INTO TraceTable
FROM ::fn_trace_gettable('D:\123.trc',default)

  然后執行以下語句:

SELECT COUNT(*) AS TotalExecutions,EventClass,
CAST(TextData AS NVARCHAR(MAX)) TextData,
SUM(Duration) AS Duration_Total, 
SUM(CPU) AS CPU_Total, SUM(Reads) AS Reads_Total, 
SUM(Writes) AS Writes_Total 
FROM TraceTable 
GROUP BY EventClass,CAST(TextData AS NVARCHAR(MAX)) 
ORDER BY Reads_Total DESC

  腳本中的TotalExecutions列指出了查詢被執行的次數,Reads_Total列指出了該查詢多次執行所進行的讀操作的總數。注意NTEXT不支持GROUP BY,因此要轉換一下類型。

  這個方法識別出來的開銷較大的查詢比Profiler識別出的單次執行的開銷較大查詢更好地指出了負載。例如,一個需要50個讀操作的查詢可能執行1000次。這個查詢本身被認為足夠經濟了,但是執行的讀操作總是是5萬,這不能被認為是經濟的。優化這個查詢降低讀操作數,即使每次執行減少10次,讀操作數也將降低1萬次。這比優化一個5千次讀操作的查詢更有利。

  從sys.dm_exec_query_stats視圖中得到相同的信息只需要一個查詢:

SELECT ss.sum_execution_count
,t.TEXT
,ss.sum_total_elapsed_time
,ss.sum_total_worker_time
,ss.sum_total_logical_reads
,ss.sum_total_logical_writes
FROM (SELECT s.plan_handle
,SUM(s.execution_count) sum_execution_count
,SUM(s.total_elapsed_time) sum_total_elapsed_time
,SUM(s.total_worker_time) sum_total_worker_time
,SUM(s.total_logical_reads) sum_total_logical_reads
,SUM(s.total_logical_writes) sum_total_logical_writes
FROM sys.dm_exec_query_stats s
GROUP BY s.plan_handle
)AS ss
CROSS APPLY  sys.dm_exec_sql_text(ss.plan_handle) t
ORDER BY sum_total_logical_reads DESC

  這比所有收集跟蹤數據所需要的工作要容易得多,那么為什么還要使用跟蹤數據?使用跟蹤的主要原因是精確性。sys.dm_exec_query_stats視圖是給定計划已經存在於內存中時的流動總計,時間點並不精確。另一方面,跟蹤是運行的任何時間段的歷史記錄。甚至可以在數據庫中加入跟蹤,並且擁有一系列可以比依靠給定的瞬間更精確地生成總計的數據。但是對定位性能問題的理解關注是查詢運行緩慢的時點,這是sys.dm_exec_query_stats不可替代的場合。

  3、識別運行緩慢的查詢

  如果運行緩慢的查詢的響應時間變得不可接受,那么應該分析性能下降的原因。但是不是所有運行緩慢的查詢都是由於資源問題造成的,其他需要關心的因素如阻塞也可能導致緩慢的查詢。

  為了發現運行緩慢的查詢,在Duration列上分組跟蹤輸出。

  

  跟蹤輸出如下:

  

  對於運行緩慢的系統,應該注意優化過程前后運行緩慢的持續查詢時間。應用優化技術之后,應該計算在系統上的總體性能。優化步驟可能負面地影響其他查詢,使其變慢。

 

 


免責聲明!

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



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