Sql Server 死鎖 死鎖捕捉 郵件提醒 監控工具
死鎖
資料庫
SELECT @@version
Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64)
Aug 22 2017 17:04:49
Copyright (C) 2017 Microsoft Corporation
Developer Edition (64-bit) on Windows 10 Enterprise 10.0 <X64> (Build 18362: )
示例資料庫
AdventureWorks2017.bak
觸發死鎖
開啟第一個查詢視窗,輸入
USE AdventureWorks2017 GO BEGIN TRAN UPDATE Purchasing.PurchaseOrderDetail SET OrderQty = OrderQty + 200 WHERE ProductID = 922 AND PurchaseOrderID = 499; GO
開啟第二個查詢視窗,輸入
USE AdventureWorks2017
GO
BEGIN TRAN
UPDATE Production.Product
SET ListPrice = ListPrice * 0.9
WHERE ProductID = 922;
回到第一個視窗,輸入以下程式碼,可以看到一直在執行。
UPDATE Production.Product
SET ListPrice = ListPrice * 1.1
WHERE ProductID = 922;
GO
現在在第二個視窗輸入以下程式碼:
UPDATE Purchasing.PurchaseOrderDetail SET OrderQty = OrderQty - 200 WHERE ProductID = 922 AND PurchaseOrderID = 499; GO
本機在3s後出現死鎖。
第一個查詢視窗中的UPDATE對錶Purchasing.PurchaseOrderDetail申請了一個X鎖。但是事務沒關閉,所以鎖沒有釋放。在第二個視窗中的UPDATE語句同樣在表Production.Product申請了X鎖,同樣鎖也沒有釋放,此時再到第一個視窗,也就是第一個事務內執行對錶Production.Product的UPDATE操作,由於第二個視窗也就是第二個事務還持有對這個表上的資源鎖,所以第一個事務會處於等待狀態。而第二個事務的UPDATE Purchasing.PurchaseOrderDetail又由於第一個事務還在持有X鎖,所以仍然在等待。最後到達了死鎖的條件,發生了死鎖。
展示了轉換死鎖的情景,A、B兩個過程都在相同的頁上持有共享鎖,每個過程都想把自己的共享鎖升級到排他鎖,但是由於共享鎖和X鎖在有多會話持有時不相容,就造成了等待。
監控死鎖的幾種方式
啟動 1222 和 1204
DBCC TRACEON(1222, -1)
GO
1204:返回參與死鎖的索梓源和型別,以及受影響的當前命令
1222:以不符合任何XSD架構的XML格式,返回參與死鎖的鎖資源和型別,以及受影響的當前命令
* 可能需要定期清理日誌
SqlServer的ERRORLOG中
2020-11-30 14:30:12.08 spid22s deadlock-list
2020-11-30 14:30:12.08 spid22s deadlock victim=process2c602046ca8
2020-11-30 14:30:12.08 spid22s process-list
2020-11-30 14:30:12.08 spid22s process id=process2c602046ca8 taskpriority=0 logused=264 waitresource=KEY: 16:72057594050904064 (3e75cd3a78e7) waittime=4928 ownerId=42727624 transactionname=user_transaction lasttranstarted=2020-11-30T14:30:00.417 XDES=0x2c5f7e14490 lockMode=U schedulerid=6 kpid=14396 status=suspended spid=66 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2020-11-30T14:30:07.153 lastbatchcompleted=2020-11-30T14:30:07.150 lastattention=2020-11-30T14:29:25.857 clientapp=Microsoft SQL Server Management Studio - 查詢 hostname=DESKTOP-6122L19 hostpid=15724 loginname=DESKTOP-6122L19\Administrator isolationlevel=read committed (2) xactid=42727624 currentdb=16 lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
2020-11-30 14:30:12.08 spid22s executionStack
2020-11-30 14:30:12.08 spid22s frame procname=adhoc line=1 stmtend=248 sqlhandle=0x020000004fbb092c29dceca676884294df83a6c4d191eec80000000000000000000000000000000000000000
2020-11-30 14:30:12.08 spid22s unknown
2020-11-30 14:30:12.08 spid22s frame procname=adhoc line=1 stmtend=248 sqlhandle=0x0200000086861218faf80bb42e2b30c275c0de82f20b50510000000000000000000000000000000000000000
2020-11-30 14:30:12.08 spid22s unknown
2020-11-30 14:30:12.08 spid22s inputbuf
2020-11-30 14:30:12.08 spid22s UPDATE Purchasing.PurchaseOrderDetail
2020-11-30 14:30:12.08 spid22s SET OrderQty = OrderQty - 200
2020-11-30 14:30:12.08 spid22s WHERE ProductID = 922
2020-11-30 14:30:12.08 spid22s AND PurchaseOrderID = 499;
2020-11-30 14:30:12.08 spid22s process id=process2c60205f468 taskpriority=0 logused=2200 waitresource=KEY: 16:72057594049921024 (bd095ec17235) waittime=8528 ownerId=42727514 transactionname=user_transaction lasttranstarted=2020-11-30T14:29:57.680 XDES=0x2c5c0258490 lockMode=X schedulerid=9 kpid=17144 status=suspended spid=59 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2020-11-30T14:30:03.553 lastbatchcompleted=2020-11-30T14:30:03.550 lastattention=1900-01-01T00:00:00.550 clientapp=Microsoft SQL Server Management Studio - 查詢 hostname=DESKTOP-6122L19 hostpid=15724 loginname=DESKTOP-6122L19\Administrator isolationlevel=read committed (2) xactid=42727514 currentdb=16 lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
2020-11-30 14:30:12.08 spid22s executionStack
2020-11-30 14:30:12.08 spid22s frame procname=adhoc line=1 stmtstart=58 stmtend=224 sqlhandle=0x02000000b946b92f64e6020ab57679e19aa9e916cc7e0da10000000000000000000000000000000000000000
2020-11-30 14:30:12.08 spid22s unknown
2020-11-30 14:30:12.08 spid22s frame procname=adhoc line=1 stmtend=166 sqlhandle=0x02000000cbda872f8f10a0c57ab5fcea19a16786794f88340000000000000000000000000000000000000000
2020-11-30 14:30:12.08 spid22s unknown
2020-11-30 14:30:12.08 spid22s inputbuf
2020-11-30 14:30:12.08 spid22s UPDATE Production.Product
2020-11-30 14:30:12.08 spid22s SET ListPrice = ListPrice * 1.1
2020-11-30 14:30:12.08 spid22s WHERE ProductID = 922;
2020-11-30 14:30:12.08 spid22s resource-list
2020-11-30 14:30:12.08 spid22s keylock hobtid=72057594050904064 dbid=16 objectname=AdventureWorks2017.Purchasing.PurchaseOrderDetail indexname=PK_PurchaseOrderDetail_PurchaseOrderID_PurchaseOrderDetailID id=lock2c5d4652780 mode=X associatedObjectId=72057594050904064
2020-11-30 14:30:12.08 spid22s owner-list
2020-11-30 14:30:12.08 spid22s owner id=process2c60205f468 mode=X
2020-11-30 14:30:12.08 spid22s waiter-list
2020-11-30 14:30:12.08 spid22s waiter id=process2c602046ca8 mode=U requestType=wait
2020-11-30 14:30:12.08 spid22s keylock hobtid=72057594049921024 dbid=16 objectname=AdventureWorks2017.Production.Product indexname=PK_Product_ProductID id=lock2c5e6001a00 mode=X associatedObjectId=72057594049921024
2020-11-30 14:30:12.08 spid22s owner-list
2020-11-30 14:30:12.08 spid22s owner id=process2c602046ca8 mode=X
2020-11-30 14:30:12.08 spid22s waiter-list
2020-11-30 14:30:12.08 spid22s waiter id=process2c60205f468 mode=X requestType=wait
2020-11-30 14:30:14.66 spid12s A significant part of sql server process memory has been paged out. This may result in a performance degradation. Duration: 655 seconds. Working set (KB): 325408, committed (KB): 656824, memory utilization: 49%.
hobid === 72057594050904064
USE AdventureWorks2017
GO
SELECT OBJECT_NAME(i.object_id) ,
i.name
FROM sys.partitions AS p
INNER JOIN sys.indexes AS i ON i.object_id = p.object_id
AND i.index_id = p.index_id
WHERE p.partition_id = 72057594050904064
使用Profiler捕獲死鎖資訊
使用Service Broker Event Notification
USE msdb;
-- 建立一個 service broker queue
CREATE QUEUE DeadlockQueue
GO
-- 建立一個 service broker service 接收事件
CREATE SERVICE DeadlockService
ON QUEUE DeadlockQueue ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification])
GO
-- 建立一個針對死鎖的事件通知
CREATE EVENT NOTIFICATION CaptureDeadlocks
ON SERVER
WITH FAN_IN
FOR DEADLOCK_GRAPH
TO SERVICE 'DeadlockService', 'current database';
GO
SELECT CAST(message_body AS XML) AS message_body FROM DeadlockQueue
使用WMI捕獲死鎖
使用ExtendedEvents捕獲死鎖
--擴充套件事件會話的資訊
select * from sys.dm_xe_sessions where name = 'system_health'
SELECT
xed.value('@timestamp','datetime')as Creation_Date,
xed.query('.')AS Extend_Event
FROM
(
SELECT CAST([target_data] AS XML)AS Target_Data
FROM sys.dm_xe_session_targets AS xt
INNER JOIN sys.dm_xe_sessions AS xs
ON xs.address= xt.event_session_address
WHERE xs.name=N'system_health'
AND xt.target_name=N'ring_buffer'
) AS XML_Data
CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]')AS XEventData(xed)
ORDER BY Creation_Date DESC
死鎖報警
實質是開啟1222,然後讀取日誌檔案,然後傳送郵件
開啟資料庫郵件傳送
IF EXISTS (
SELECT 1 FROM sys.configurations
WHERE NAME = 'Database Mail XPs' AND VALUE = 0)
BEGIN
PRINT 'Enabling Database Mail XPs'
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE
EXEC sp_configure 'Database Mail XPs', 1;
RECONFIGURE
END
配置資料庫郵件
新建作業,設定警報,設定步驟
DECLARE @starttime VARCHAR(30),
@endtime VARCHAR(30),
@Cmd VARCHAR(500),
@servername NVARCHAR(150),
@mysubject NVARCHAR(200),
@body VARCHAR(2000)
SET @endtime = CONVERT(VARCHAR(30), GETDATE(), 126)
SET @starttime = CONVERT(VARCHAR(30), DATEADD(MI, -1, GETDATE()), 126);
SET @Cmd = 'EXEC master.dbo.xp_readerrorlog 0, 1, null, null, ' + '''' + @starttime + '''' + ', '
+ '''' + @endtime + '''' + ', ' + 'N''ASC'''
SET @servername = @@servername
SET @mysubject = '[Warning]:Deadlock event notification on server ' + @servername + ' at '+@starttime
SET @body = N'Deadlock has occurred.Please refer to attachement or use below sql statement to check deadlock detalis:
' + @Cmd
EXEC msdb.dbo.sp_send_dbmail
@profile_name='DBMailProfile',
@recipients='[email protected]',
@subject=@mysubject,
@body=@body,
@query=@Cmd,
@attach_query_result_as_file=1,
@query_attachment_filename=N'deadlock log.txt',
@query_result_width=32767,
@exclude_query_output=1,
@append_query_error=1;
為什麼查詢慢?是不是死鎖了?
這個問題被大量的開發人員問過。查詢慢有很多情況,歸根結底是資源問題,但是絕大部分情況是由於設計、編碼導致的。不合理、低效地操作資料庫,導致資源利用不合理甚至不足,從而發生效能問題。查詢慢主要是因為在併發特別是悲觀併發模式下,互相阻塞和鎖過多、過久造成的其他會話等待,甚至死鎖,從而表現出來執行慢。至於死鎖導致查詢慢,其實很少見,因為在通常情況下,死鎖5s內就會被SQL Server終止。所以更準確地來說,是阻塞而不是死鎖導致慢。