1. 程式人生 > >處理鎖、阻塞和死鎖(2)——偵測阻塞和阻塞查詢

處理鎖、阻塞和死鎖(2)——偵測阻塞和阻塞查詢

前言:

如果一個事務正在等待一些給其他事務鎖定的資源。這個事務就被成為“被阻塞的事務”。反過來,引起阻塞的事務,也就是鎖定資源並造成其他事務等待的事務叫做“正在阻塞的事務”。

長時間執行事務會阻塞其他事務和查詢,使他們等待長時間。在繁重的系統中,很多時候我們會遇到阻塞問題,如果一個事務因為阻塞未完成。會造成一些列的等待鏈。

本文將介紹如何發現並馬上解決這方面的問題。

準備工作:

本例依舊使用SQLServer2012上的AdventureWorks2012資料庫。

步驟:

1、 連到SQLServer2012的AdventureWorks2012資料庫。

2、 新建視窗並輸入:

[sql] view plain
copyprint?
  1. USE AdventureWorks2012  
  2. GO  
  3. SETTRANSACTIONISOLATIONLEVELREPEATABLEREAD
  4. GO  
  5. --開啟事務
  6. BEGINTRANSACTION
  7. --獲取會話ID
  8. SELECT  @@SPID AS Connection1_SessionID  
  9. SELECT  *  
  10. FROM    Sales.SalesOrderDetail  
  11. WHERE   SalesOrderDetailID = 121316  
USE AdventureWorks2012
GO
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO

--開啟事務
BEGIN TRANSACTION

--獲取會話ID
SELECT  @@SPID AS Connection1_SessionID

SELECT  *
FROM    Sales.SalesOrderDetail
WHERE   SalesOrderDetailID = 121316


3、 執行完之後,截圖如下:


4、 新開另外一個視窗,輸入下面程式碼去開啟另外一個事務,留意UPDATE語句,將不會執行,因為在等待第二步中的事務:

[sql] view plaincopyprint?
  1. USE AdventureWorks2012  
  2. GO  
  3. --開啟事務
  4. BEGINTRANSACTION
  5. UPDATE  Sales.SalesOrderDetail  
  6. SET     OrderQty = 10  
  7. WHERE   SalesOrderDetailID = 121316  
  8. COMMITTRANSACTION
USE AdventureWorks2012
GO

--開啟事務
BEGIN TRANSACTION

UPDATE  Sales.SalesOrderDetail
SET     OrderQty = 10
WHERE   SalesOrderDetailID = 121316

COMMIT TRANSACTION


5、 再開啟一個事務,輸入以下程式碼查詢被阻塞和正在阻塞的查詢: 

[sql] view plaincopyprint?
  1. SELECT  R.session_id AS BlockedSessionID ,  
  2.         S.session_id AS BlockingSessionID ,  
  3.         Q1.text AS BlockedSession_TSQL ,  
  4.         Q2.text AS BlockingSession_TSQL ,  
  5.         C1.most_recent_sql_handle AS BlockedSession_SQLHandle ,  
  6.         C2.most_recent_sql_handle AS BlockingSession_SQLHandle ,  
  7.         S.original_login_name AS BlockingSession_LoginName ,  
  8.         S.program_name AS BlockingSession_ApplicationName ,  
  9.         S.host_name AS BlockingSession_HostName  
  10. FROM    sys.dm_exec_requests AS R  
  11. INNERJOIN sys.dm_exec_sessions AS S ON R.blocking_session_id = S.session_id  
  12. INNERJOIN sys.dm_exec_connections AS C1 ON R.session_id = C1.most_recent_session_id  
  13. INNERJOIN sys.dm_exec_connections AS C2 ON S.session_id = C2.most_recent_session_id  
  14. CROSS APPLY sys.dm_exec_sql_text(C1.most_recent_sql_handle) AS Q1  
  15. CROSS APPLY sys.dm_exec_sql_text(C2.most_recent_sql_handle) AS Q2  
SELECT  R.session_id AS BlockedSessionID ,
        S.session_id AS BlockingSessionID ,
        Q1.text AS BlockedSession_TSQL ,
        Q2.text AS BlockingSession_TSQL ,
        C1.most_recent_sql_handle AS BlockedSession_SQLHandle ,
        C2.most_recent_sql_handle AS BlockingSession_SQLHandle ,
        S.original_login_name AS BlockingSession_LoginName ,
        S.program_name AS BlockingSession_ApplicationName ,
        S.host_name AS BlockingSession_HostName
FROM    sys.dm_exec_requests AS R
        INNER JOIN sys.dm_exec_sessions AS S ON R.blocking_session_id = S.session_id
        INNER JOIN sys.dm_exec_connections AS C1 ON R.session_id = C1.most_recent_session_id
        INNER JOIN sys.dm_exec_connections AS C2 ON S.session_id = C2.most_recent_session_id
        CROSS APPLY sys.dm_exec_sql_text(C1.most_recent_sql_handle) AS Q1
        CROSS APPLY sys.dm_exec_sql_text(C2.most_recent_sql_handle) AS Q2



6、 因為第一個連線佔用了資源,阻塞了其他事務,所以這裡要結束這個程序:

[sql] view plaincopyprint?
  1. KILL 68  
  2. GO  
KILL 68
GO



7、 換回第二個查詢介面,發現update操作已經成功完成。上面的程序號根據不同機器而定。

分析:

在本例中,把事務隔離級別設為REPEATABLE READ,因為在這個隔離級別中,在資源上的共享鎖將持續到事務完成。所以當從表中查詢資料是,該值上會加上共享鎖。在事務提交或回滾前不會釋放。

當執行第二個連線的update語句時,不能完成,因為被第一個事務阻塞了,且在REPEATABLE READ下共享鎖不釋放。

為了標識阻塞和被阻塞的請求,需要用到下面的DMO:

1、 dm_exec_requests

2、 dm_exec_sessions

3、 dm_exec_connections

4、 dm_exec_sql_text