SQL查詢性能分析

原文: SQL查詢性能分析

原文出處:http://blog.csdn.net/dba_huangzj/article/details/7623926

SQL查詢性能的好壞直接影響到整個數據庫的價值,對此,必須鄭重對待。sql

SQL Server提供了多種工具,下面作一個簡單的介紹:數據庫

 

1、SQL Profiler工具緩存

SQL Profiler可用於:安全

l  圖形化監視SQLServer查詢;服務器

l  在後臺收集查詢信息;函數

l  分析性能;工具

l  診斷像死鎖這樣的問題;性能

l  調試Transact-SQL(T-SQL)語句;學習

l  模擬重放SQLServer活動大數據

 

注意:定義一個跟蹤最有效的方法是經過系統存儲過程,可是學習的起點仍是經過GUI。

 

1.一、  Profiler跟蹤:

建議使用標準模版

1.二、  事件:

一個事件表現SQLServer中執行的各類活動。能夠簡單分類爲:事件類、遊標事件、鎖事件、存儲過程事件和T-SQL事件。

對於性能分析,主要關心如下部分:

l  SQL活動涉及哪一類的CPU使用?

l  使用了多少內存?

l  涉及多少I/O操做?

l  SQL活動執行了多長時間?

l  特定的查詢執行的頻率多高?

l  查詢面對哪類錯誤和警告?

跟蹤查詢結束的事件:

事件類

事件

描述

Stored Procedures

RPC:Completed

RPC完成事件

SP:Completed

存儲過程完成事件

SP:StmtCompleted

在存儲過程當中一條SQL語句完成事件

TSQL

SQL:BatchCompleted

T-SQL批完成事件

SQL:StmtCompleted

一條T-SQL語句完成事件

RPC事件表示存儲過程使用遠程過程調用(RPC)機制經過OLEDB命令執行。若是一個數據庫應用程序使用T-SQL EXECUTE語句執行一個存儲過程,那麼會被轉化爲一個SQL批而不是一個RPC,RPC一般比EXECUTE請求快,由於它們繞過了SQLServer中的許多語句解析和參數處理。

         T-SQL批是一組被一塊兒提交到SQLServer的SQL查詢,以GO結束。GO不是一條T-SQL語句,而是有Sqlcmd使用程序和Management Studio識別。象徵着批的結束。T-SQL批由一條或多條T-SQL語句組成。語句或T-SQL語句在存儲過程(如下簡稱SP)中也是獨立和離散的。用SP:StmtCompleted或SQL:StmtCompleted事件捕獲單獨的語句可能代價很高。收集時要很是謹慎,特別在生產環境上。

跟蹤查詢性能的事件:

事件類

事件

描述

Security Audit(安全審計)

Audit Login(登陸審計)

記錄用戶鏈接到SQL Server或斷開鏈接時數據庫的鏈接

Audit Logou(註銷審計)

Seesions(會話)

ExistingConnection(現有鏈接)

表示全部在跟蹤開始以前鏈接到SQLServer的用戶

Cursors(遊標)

CursorImplicitConversion(遊標隱含轉換)

代表建立的遊標類型與所請求的類型不一樣。

Errors and Warnings(錯誤和警告)

Attention(注意)

表示因爲客戶撤銷查詢或者數據庫鏈接破壞引發的請求中斷

Exception(異常)

代表SQLServer中發生了異常

Execution Warnings(執行警告)

代表在查詢或SP執行過程當中出現了警告

Hash Warning(hash警告)

代表hash操做中發生了錯誤

Missing Column Statistics(列統計丟失)

代表優化器要求的肯定處理策略用的列統計丟失。

Missing Join Predicate(鏈接斷言丟失)

代表查詢在兩表之間沒有鏈接斷言狀況下執行。

Sort Warnings(排序警告)

代表像select這樣的查詢中執行的排序操做沒有合適的內存。

Locks(鎖)

Lock: Deadlock(死鎖)

標誌着死鎖的出現

Lock: Deadlock Chain(死鎖鏈)

顯示產生死鎖的查詢鏈條

Lock: Timeout(鎖超時)

表示鎖已經超過了其超時參數,該參數由SET LOCK_TIMEOUT timeout_period(MS)命令設置

Stored Procedures(存儲過程)

SP:Recompile(重編譯)

代表用於一個存儲過程的執行計劃必須重編譯,緣由是執行計劃不存在,強制的重編譯,或者現有的執行計劃不能重用。

SP:Starting(開始)

SP:StmtStarting(語句開始)

分別表示一個SP:StmtStarting存儲過程和存儲過程當中的一條SQL語句的開始。它們對於識別開始但由於一個操做致使Attention事件而未能結束的查詢頗有用。

Transactions(事務)

SQLTransaction(SQL事務)

提供數據庫事務的信息,包括事務開始/結束的時間、事務持續時間的信息。

 

1.三、  數據列:事件的特性。如事件的類、用於該事件的SQL語句、鎖資源開銷及事件來源。

數據列

描述

EventClass(事件類)

事件類型,如SQL:StatementCompleted

TextData

事件所用的SQL語句

CPU

事件的CPU開銷(ms)

Reads

爲一個事件所執行的邏輯讀操做數量。

Writes

一個事件所執行的邏輯寫操做數量。

Duration

事件的執行事件(ms)

SPID

該事件的進程ID

StratTime

事件開始的事件

邏輯讀、寫由內存中的8KB頁面活動組成,可能須要0或者多個物理I/O。找到物理I/O操做數,使用系統監視工具。

 

2、跟蹤的自動化

注意:SQL Profiler對性能存在負面影響,如非必要不要在生產環境長期使用。

1.        使用GUI捕捉跟蹤:

可使用兩種方法建立腳本化的跟蹤——手工或GUI:

可使用Profiler的導出功能導出腳本。

2.        使用存儲過程捕捉跟蹤:

l  Sp_trace_create:建立一個跟蹤定義。

l  Sp_trace_setevent:添加事件和事件列到跟蹤中。

l  Sp_trace_setfilter:將過濾器應用到跟蹤。

可使用內建函數:fn_trace_getinfo肯定正在運行的跟蹤:

SELECT * FROM ::fn_trace_getinfo(default);


可使用:sp_trace_setstatus中止特定的跟蹤:

EXEC sp_trace_setstatus 1,0

—中止id爲1的跟蹤。

關閉跟蹤後,必須刪除:

EXEC sp_trace_setstatus 1,2


能夠從新執行fn_trace_getinfo函數確認是否已經關閉。

 

3、結合跟蹤和性能監視器輸出

能夠結合SQL Profiler和性能監視器來分析性能,此處很少說

 

4、SQL Profiler建議

使用SQL Profiler時,要考慮如下幾點:

l  限制事件和數據列的數量;

l  拋棄用於性能分析的啓動事件;

l  限制跟蹤輸出大小;

l  避免聯機數據列排序;

l  遠程運行Profiler

 

一、  限制事件和數據列:

捕捉像鎖和執行計劃這樣的事件時應該當心進行,由於輸出會變得很是大並下降SQL Server性能。

二、  丟棄性能分析所用的啓動事件:

像SP:StmtStarting這樣的啓動事件不提供分析信息,由於只有事件完成才能計算I/O量、CPU負載和查詢的持續時間。

使用捕捉啓動事件的時機是:預期某些SQL查詢由於錯誤而不能結束執行,或者頻繁發現Attention事件按的時候捕捉。由於Attention事件通常表示用戶中途撤銷了查詢或者查詢超時,可能由於查詢運行了太長時間。

三、  限制跟蹤輸出大小:

在Edit Filter(編輯過濾器)對話框中作如下設置:

l  Duration-Greater than or equal:2(持續事件>=2):持續事件等於0或1ms的查詢不能進一步優化。

l  Reads-Greater than or equal:2(讀操做數量>=2):邏輯讀數量等於0或1的查詢不能進一步優化。

四、  避免在線數據列排序:

(1)、捕捉跟蹤,不作任何排序或分組。

(2)、保存跟蹤輸出到一個跟蹤文件。

(3)、打開跟蹤文件並按照須要排序。

五、  遠程運行Profiler:

使用系統存儲過程比使用GUI對性能方面有好處。

六、  限制使用某些事件:在已經遇到壓力的系統上,不要使用Showplan XML事件

 

 

5、沒有Profiler狀況下的查詢性能度量

對於須要當即捕捉系統,使用DMV:sys.dm_exec_query_stats比Profiler有效,若是須要查詢運行機器單獨開銷的歷史記錄,跟蹤還是更好的工具。

sys.dm_exec_query_stats:獲取服務器上查詢計劃統計的信息:

描述

Plan_handle

引用執行計劃的指針

Creation_time

計劃建立的時間

Last_execution time

查詢最後一次使用計劃的時間

Execution_count

計劃已經使用的次數

Total_worker_time

從建立起計劃使用的CPU時間

Total_logical_reads

從建立起計劃使用的讀操做數量

Total_logical_writes

從建立起計劃使用的寫操做數量

Query_hash

可用於識別有相似邏輯的查詢的一個二進制hash

Query_plan_hash

可用於識別有類似邏輯的計劃的一個二進制hash

爲了過濾信息,須要關聯其餘DMF。如sys.dm_exec_sql_text來查看查詢文本。

Sys.dm_query_plan顯示查詢的執行計劃。從而限制沒必要要的返回信息。

 

6、開銷較大的查詢

對於收集結果,應該分析兩部分:

l  致使大量系統資源壓力的查詢;

l  速度下降最嚴重的查詢

 

一、  識別開銷較大的查詢:

對於返回的跟蹤數據,CPU和Reads列顯示了查詢開銷所在。在執行讀操做時,內存頁面必須在操做查詢中被備份,在第一次數據訪問期間寫入,並在內存瓶頸時被移到磁盤。過多頁面CPU還會增長管理頁面的負擔。

           致使大量邏輯讀的查詢一般在相應的大數據集上獲得鎖。即便讀,也須要在全部數據上的共享鎖。阻塞了其餘請求修改的查詢。但不阻塞讀數據的查詢。若是查詢好久,那麼會持續阻塞其餘查詢,被阻塞的查詢進一步阻塞其餘查詢,引發數據中的阻塞鏈。

結論,識別開銷大的查詢並首先優化它們從而達到如下效果:

l  增進開銷較大的查詢自己的性能;

l  下降系統資源上的整體壓力;

l  減小數據庫阻塞;

開銷大的查詢有兩類:

l  單次執行:查詢一次開銷較大

l  屢次執行:查詢自己不大,可是重複執行致使系統資源上的壓力。

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

可使用SQL Profiler,或者查詢sys.dm_exec_query_stats來識別開銷大的查詢。

(1)、捕捉表示典型工做負載的Profiler跟蹤。

(2)、將跟蹤輸出保存到一個跟蹤文件。

(3)、打開跟蹤文件進行分析。

(4)、打開跟蹤的Properties(屬性)窗口,單擊Event Selection(事件選擇)選項卡。

(5)、單機按鈕打開Organize Columns(組織列)窗口。

(6)、在Reads列上分組跟蹤輸出。

(7)、使用分組的跟蹤。

2.      屢次執行開銷較大的查詢:

l  這種狀況下,Profiler中跟蹤輸出的如下列上分組:EventClass、TextData和Reads。

l  導出Profiler跟蹤表。使用內建函數fn_trace_gettable導入到一個跟蹤表。

l  訪問sys.dm_exec_query_statsDMV從生產服務器檢索信息。

把數據裝入到數據庫的一個表中

SELECT  *
INTO    Trace_Table
FROM    ::
        FN_TRACE_GETTABLE('C:\PerformanceTrace.trc', DEFAULT)


 

執行下面語句查詢屢次執行的讀操做總數:

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


SQL Server 2008不支持在NTEXT數據類型進行分組。而TextDatantext類型,要轉換成Nvarcharmax

 

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_readsDESC


 

3.      識別運行緩慢的查詢:

須要按期監視輸入的SQL查詢的執行時間,並找出運行緩慢的查詢的響應時間。可是不是全部運行緩慢的查詢都是因爲資源問題造成。如阻塞那些都有可能致使緩慢的查詢。

能夠在Duration上跟蹤。

 

 

7、執行計劃

一、  分析查詢計劃

執行計劃從右到左,從上到下的順序閱讀。每一個步驟表明得到查詢最終輸出所執行的操做。執行計劃有如下特徵:

l  若是查詢由多個查詢的批組成,每一個查詢的執行計劃按照執行的順序顯示。批中的每一個執行將有一個相對的估算開銷,整個批的總開銷爲100%。

l  執行計劃中的每一個圖標表明一個操做符。有相對的估算開銷,全部節點的總開銷爲100%。

l  執行計劃中的一個起始操做符一般表示一個數據庫對象(表或索引)的數據檢索機制。

l  數據檢索一般是一個表操做或索引操做。

l  索引上的數據檢索將是索引掃描或索引查找。

l  索引上的數據檢索的命名慣例是[表名].[索引名]。

l  數據從右到左在兩個操做之間流動,由一個鏈接箭頭表示。

l  操做符之間鏈接箭頭的寬度是傳輸行數的圖形表示。

l  同一列的兩個操做符之間的鏈接機制將是嵌套的循環鏈接,hash匹配鏈接或者合併鏈接。

l  將光標放置在執行計劃的一個節點上,顯示一個具備一些細節的彈出窗口。

l  在Properties(屬性)窗口中有完整的一組關於操做符的細節。能夠右鍵單擊操做符並選擇Properties。

l  操做符細節在頂部顯示物理和邏輯操做的類型。物理操做表明存儲引擎實際使用的,而邏輯操做是優化器用於創建估算執行計劃的結構。若是相同,只顯示物理操做。還會顯示其餘信息:I/O、CPU等。

l  操做符細節彈出窗口的Argument(參數)部分在分析中特別有用,由於顯示了優化器鎖使用的過濾或鏈接條件。

二、  識別執行計劃中開銷較大的步驟:

l  執行計劃中每一個節點顯示整個計劃中的相對開銷,整個計劃總開銷爲100%。關注最高相對開銷的節點。

l  執行計劃可能來自於一批語句,所以可能也須要查找開銷最大的語句。

l  查看節點之間鏈接箭頭的寬度。很是寬的鏈接箭頭表示對應節點之間的傳輸大量的行。分析箭頭左邊的節點以理解須要這麼多行的緣由,還要檢查箭頭的屬性。可能看到估計的行和實際的行不同,這可能由過期的統計形成。

l  尋找hash鏈接操做。對於小的數據集,嵌套的循環鏈接一般是首選的鏈接技術。

l  尋找書籤查找操做。對於大結果集的書籤操做可能形成大量的邏輯讀。

l  若是操做符上有一個歎號的警告,是須要馬上注意的領域。這些警告多是由各類問題形成的,包括沒有鏈接條件的鏈接或者丟失統計的索引和表。

l  需找執行排序操做的步驟,這表示數據沒有以正確的排序進行檢索。

 

三、  分析索引有效性:

要關注【掃描】,掃描表明訪問大量的行。能夠經過如下方式判斷索引有效性:

l  數據檢索操做

l  鏈接操做

有時候執行計劃中沒有【斷言】(predicate),缺少斷言意味着整個表(聚簇索引就是該表)被做爲合併鏈接操做符的輸入進行掃描。

四、  分析鏈接有效性:

SQLServer使用3中鏈接類型:

l  Hash鏈接;

l  合併鏈接

l  嵌套循環鏈接

一、  Hash鏈接:

1.一、       Hash鏈接高效處理大的、未排序的、沒有索引的輸入。

1.二、       Hash鏈接使用兩個鏈接輸入:創建輸入(build input)和探查輸入(probe input)。創建輸入是執行計劃中上面的那個輸入,探查輸入是下面那個輸入。

1.三、       最多見的hash鏈接方式——in-memory hash join,整個創建輸入被掃描或計算而後在內存中創建一個hash表。每一個行根據計算的hash鍵值(相等斷言中的一組列)被插入一個hash表元中。

內存hash鏈接的示意圖:


二、  合併鏈接:

2.一、合併鏈接要求兩個輸入在合併列上排序,這將在鏈接條件中定義。若是兩個鏈接有索引,那麼鏈接輸入由該索引排序。因爲每一個鏈接輸入都被排序了,合併排序從每一個輸入獲得一行並比較是否相等。若是相等,匹配行被生成。過程被重複到全部行都被處理。

2.二、若是優化器發現鏈接輸入都在其鏈接列上排序,合併鏈接就比hash鏈接更快而被選中。

三、  嵌套循環鏈接:

3.一、始終從單獨的表中訪問有限數量的行,爲了理解使用較小結果集的效果,在查詢中下降鏈接輸入。

3.二、使用一個鏈接輸入做爲外部(outer)輸入表。另外一個做爲內部(inner)輸入表。外部表是執行計劃的上方輸入,內部表是下方輸入。外部循環逐行消費外部輸入表。內部循環爲每一個外部行執行一次,搜索內部輸入表的匹配行。

3.三、若是外部輸入至關小,內部輸入大但有索引,嵌套循環鏈接是很是高效的。鏈接經過犧牲其餘方面來提升速度——使用內存來取得小的數據集並快速與第二個數據集比較。合併排序與此相似,使用內存和一小部分tempdb排序,hash鏈接使用內存和tempdb創建hash表。

3.四、雖然循環鏈接更快,可是隨着數據集變得更大,比hash或合併消耗更多的內存。因此SQL Server會在不一樣數據集的狀況下使用不一樣計劃的緣由。

 

3種鏈接類型的特性:

鏈接類型

鏈接列上的索引

鏈接表的通常大小

預先排序

鏈接子句

Hash

內部表:不須要索引

外部表:可選

最佳條件:小的外部表,大的內部表

任意

不須要

Equi-join

合併

內部/外部表:必須

最佳條件:兩個表都有聚簇索引或覆蓋索引

須要

Equi-join

嵌套循環

內部表:必須

外部表:最好有

可選

全部

注意:在hash和嵌套循環鏈接中,外部表通常是兩個鏈接表中較小的一個。

五、  實際執行計劃vs估算執行計劃:

估算執行計劃對臨時表沒法生成。

六、  計劃緩存:

通常是保存在內存空間。可使用DMV來查詢:

SELECT  p.query_plan ,
        t.text
FROM    sys.dm_exec_cached_plansr
        CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) p
        CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) t


8、查詢開銷

一、  客戶統計:將計算機做爲服務器的一個客戶端,從這個角度去發出捕捉執行信息。

點擊SSMS中的【查詢】→【包含客戶統計】,但這一步不是很好的收集方法。有時候須要重置:【查詢】→【重置客戶統計】

二、  執行時間:

Duration和CPU都表明着查詢的時間因素,可使用SET STATISTICS TIME來取得執行時間。


其中最後一行的CPU時間等於Profiler的CPU值,佔用時間表明Duration值。0毫秒的分析和編譯時間說明重用了執行計劃。能夠執行:DBCC FREEPROCCACHE清除緩存。可是不要在生產系統上執行,由於某種狀況下,這和重啓的開銷相同。

三、  STATISTICS IO:

Profiler獲取的Reads列的讀取次數嚐嚐是Duration、CPU、Reads和Writes這些因素中最重要的。在解讀STATISTICS IO的輸出時,多半參考【邏輯讀】操做。有時候也會參考掃描計數。物理讀操做和預讀數量在數據不能在內存中找到時將不爲0,但一旦數據填寫到內存,物理讀和預讀將趨向於0。在優化期間,能夠監控單表的讀操做次數以確保確實減小了該表的數據訪問開銷。

相關文章
相關標籤/搜索