等待大概分爲3類:資源等待、隊列等待、外部等待sql
過濾掉系統相關的等待類型的語句。(查看經常使用的等待信息)數據庫
SELECT wait_type , signal_wait_time_ms , wait_time_ms FROM sys.dm_os_wait_stats WHERE wait_time_ms > 0 AND wait_type NOT IN ( 'CLR_SEMAPHORE', 'CLR_AUTO_EVENT', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK', 'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE', 'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT', 'BROKER_TO_FLUSH', 'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'DISPATCHER_QUEUE_SEMAPHORE', 'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP' ) ORDER BY signal_wait_time_ms DESC
生產環境中使用:緩存
DBCC SQLPERF('sys.dm_os_wait_stats',CLEAR)
當A正在更新一個表並把表鎖住時,B也想去讀這個表,此時B就必須等待A完成。對於這種狀況,可使用DMV:sys.dm_os_waiting_tasks查看當前正在處於等待狀態的會話(sessions),並展現會等待的資源。若是某個會話正在等待某些資源,那麼這個DMV結果中的blocking_session_id列就會有這個Session_id服務器
另外一個DMV:sys.dm_exec_requests用於返回當前實例上每一個用戶和內部的鏈接信息session
常見的等待類型:併發
1.並行執行 2.多任務等待 3.I/O等待 4.備份還原等待 5.鎖定等待 6.數據庫日誌等待 7.外部資源等待數據庫設計
一:並行執行性能
並行操做最多見的等待類型是CXPACKET測試
若是是OLTP系統,理想狀況下事務很短,就沒有必要經過並行運行來提升運行速度了,極端方法,把最大並行度設爲1,強制SQL Server 不去使用並行操做,從而減小沒必要要的資源等待優化
SELECT * FROM sys.configurations WHERE name LIKE '%Max Degree of Parallelism%' GO EXEC sys.sp_configure N'show advanced options', N'1' GO RECONFIGURE GO EXEC sys.sp_configure N'Max Degree of Parallelism', N'1' GO RECONFIGURE
若是是OLAP系統,因爲事務廣泛較長,因此並行操做每每能提升速度和資源利用率。把最大並行度設爲0
如下的腳本用於查詢計劃緩存中存在並行查詢的語句
SELECT TOP 10 p.* , q.* , qs.* , cp.plan_handle FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.Dm_exec_query_plan(cp.plan_handle) p CROSS APPLY sys.Dm_exec_sql_text(cp.plan_handle) AS q JOIN sys.dm_exec_query_stats qs ON qs.plan_handle = cp.plan_handle WHERE cp.cacheobjtype = 'Compiled Plan' AND p.query_plan.value('declare namespace p="http://schemas.microsoft.com/SQL Server/2004/07/showplan"; max(//p:RelOp/@Parallel)', 'float') > 0 OPTION ( MAXDOP 1 )
CXPACKET潛在問題:
一個服務器上部署OLTP和OLAP
EXEC sys.sp_configure N'cost threshold for parallelism',N'25' EXEC sys.sp_configure N'Max Degree of Parallelism',N'2' RECONFIGURE WITH OVERRIDE --刷新數據庫的配置
常見的引發CXPACKET等待類型的狀況:
1.在可變類型中數據的分佈存在嚴重傾斜,某列varchar類型的數據,有些數據的長度是60bytes,有些卻達到500bytes,對這樣的數據進行查詢時,會致使執行計劃不夠高效,也會致使統計信息的可參考性下降。在並行執行時,容易出現某個線程執行很快但另一個執行很慢的狀況,從而增長了CXPACKET的出現機率。
2.在併發的過程當中,若是一個線程出現了資源瓶頸,會致使這個線程的速度比其餘線程要慢,從而影響總體的運行速度。
3.查詢所須要的數據存放在不一樣的I/O子系統中,而這些子系統的性能又存在差別最終的結果跟上面的第二種狀況相似。
4.查詢所須要的數據中,不一樣部分的碎皮不一樣,所須要的I/O也不一樣。I/O數量直接影響運行速度和資源開銷,甚至影響執行計劃的生成,從而也致使了查詢過程當中不一樣線程部分的運行速度出現差別。
CXPACKET建議:
1.碎片問題,則減小碎片。
2.從物理文件的存放上要避免出現同一查詢的不一樣部分由於I/O性能差別而出現差別。簡單來講就是要保證數據文件所在的盤性能相等
3.儘量保持統計信息的實時性
4.過多的線程會致使上下文切換開銷,也容易引發CXPACkET等待,因此在改動這方面配置時,須要進行嚴謹的測試和監控
5.絕大部分性能問題的終極方案----優化,從數據庫設計、查詢編碼、索引設計上進行優化
6.最多見的問題是因爲查詢性能太低,致使SQL Server選擇了並行操做,而並行操做又存在一些問題
7.把前面的cost threshold parallelism的值設高
在SQL Server 運行過程當中,經常會有不一樣類型的任務在運行,其中由這種操做產生的等待類型最多見的是SOS_SCHEDULER_YIELD
SOS_SCHEDULER_YIELD等待類型就發生在一個任務自願放棄當前的資源佔用,讓給其餘任務使用的時候。
用sys.dm_os_sehedulers看看當前有多少runnable的任務在系統中運行
SELECT scheduler_id,current_tasks_count,runnable_tasks_count,work_queue_count,pending_disk_io_count FROM sys.dm_os_schedulers WHERE scheduler_id<255
關注runnable_tasks_count這個列的數據,若是見到長時間存在兩位數的數值,意味着CPU可能存在壓力,沒法應對當前負載。
下降SOS_SCHEDULER_YIELD等待。
查看使用CPU最多的查詢語句,針對這些結果來進行優化,還能夠查找運行時間最長的腳本進行優化。
SELECT SUBSTRING(qt.text, ( qs.statement_start_offset / 2 ) + 1, ( ( CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(qt.text) ELSE qs.statement_end_offset END - qs.statement_start_offset ) / 2 ) + 1) , qs.execution_count , qs.total_logical_reads , qs.last_logical_reads , qs.total_logical_writes , qs.last_logical_writes , qs.total_worker_time , qs.last_worker_time , qs.total_elapsed_time / 1000000 AS total_elapsed_time_in_S , qs.last_elapsed_time / 1000000 AS last_elapsed_time_in_S , qs.last_execution_time , qp.query_plan FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt CROSS APPLY sys.dm_exec_query_plan(qs.sql_handle) qp ORDER BY qs.total_worker_time DESC --CPU時間
檢查 活動事務的日誌狀況腳本。
SELECT DTST.[session_id] , DES.[login_name] AS [Login Name] , DB_NAME(DTDT.database_id) AS [Database] , DTDT.[database_transaction_begin_time] AS [Begin Time] , -- DATEDIFF(ms,DTDT.[database_transaction_begin_time], GETDATE()) AS [Durationms], CASE DTAT.transaction_type WHEN 1 THEN 'Read/write' WHEN 2 THEN 'Read-only' WHEN 3 THEN 'System' WHEN 4 THEN 'Distributed' END AS [Transaction Type] , CASE DTAT.transaction_state WHEN 0 THEN 'Not fully initialized' WHEN 1 THEN 'Initialized, not started' WHEN 2 THEN 'Active' WHEN 3 THEN 'Ended' WHEN 4 THEN 'Commit initiated' WHEN 5 THEN 'Prepared, awaiting resolution' WHEN 6 THEN 'Committed' WHEN 7 THEN 'Rolling back' WHEN 8 THEN 'Rolled back' END AS [Transaction State] , DTDT.[database_transaction_log_record_count] AS [Log Records] , DTDT.[database_transaction_log_bytes_used] AS [Log Bytes Used] , DTDT.[database_transaction_log_bytes_reserved] AS [Log Bytes RSVPd] , DEST.[text] AS [Last Transaction Text] , DEQP.[query_plan] AS [Last Query Plan] FROM sys.dm_tran_database_transactions DTDT INNER JOIN sys.dm_tran_session_transactions DTST ON DTST.[transaction_id] = DTDT.[transaction_id] INNER JOIN sys.[dm_tran_active_transactions] DTAT ON DTST.[transaction_id] = DTAT.[transaction_id] INNER JOIN sys.[dm_exec_sessions] DES ON DES.[session_id] = DTST.[session_id] INNER JOIN sys.dm_exec_connections DEC ON DEC.[session_id] = DTST.[session_id] LEFT JOIN sys.dm_exec_requests DER ON DER.[session_id] = DTST.[session_id] CROSS APPLY sys.dm_exec_sql_text(DEC.[most_recent_sql_handle]) AS DEST OUTER APPLY sys.dm_exec_query_plan(DER.[plan_handle]) AS DEQP ORDER BY DTDT.[database_transaction_log_bytes_used] DESC; -- ORDER BY [Duration ms] DESC;