處理鎖、阻塞和死鎖(2)——偵測阻塞和阻塞查詢
阿新 • • 發佈:2019-02-12
前言:
如果一個事務正在等待一些給其他事務鎖定的資源。這個事務就被成為“被阻塞的事務”。反過來,引起阻塞的事務,也就是鎖定資源並造成其他事務等待的事務叫做“正在阻塞的事務”。
長時間執行事務會阻塞其他事務和查詢,使他們等待長時間。在繁重的系統中,很多時候我們會遇到阻塞問題,如果一個事務因為阻塞未完成。會造成一些列的等待鏈。
本文將介紹如何發現並馬上解決這方面的問題。
準備工作:
本例依舊使用SQLServer2012上的AdventureWorks2012資料庫。
步驟:
1、 連到SQLServer2012的AdventureWorks2012資料庫。
2、 新建視窗並輸入:
[sql] view plain- USE AdventureWorks2012
- GO
- SETTRANSACTIONISOLATIONLEVELREPEATABLEREAD
- GO
- --開啟事務
- BEGINTRANSACTION
- --獲取會話ID
- SELECT @@SPID AS Connection1_SessionID
- SELECT *
- FROM Sales.SalesOrderDetail
- 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?- USE AdventureWorks2012
- GO
- --開啟事務
- BEGINTRANSACTION
- UPDATE Sales.SalesOrderDetail
- SET OrderQty = 10
- WHERE SalesOrderDetailID = 121316
- COMMITTRANSACTION
USE AdventureWorks2012 GO --開啟事務 BEGIN TRANSACTION UPDATE Sales.SalesOrderDetail SET OrderQty = 10 WHERE SalesOrderDetailID = 121316 COMMIT TRANSACTION
5、 再開啟一個事務,輸入以下程式碼查詢被阻塞和正在阻塞的查詢:
[sql] view plaincopyprint?- 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
- INNERJOIN sys.dm_exec_sessions AS S ON R.blocking_session_id = S.session_id
- INNERJOIN sys.dm_exec_connections AS C1 ON R.session_id = C1.most_recent_session_id
- INNERJOIN 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
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?- KILL 68
- 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