日常工作中,经常会出现一些死锁现象发生,影响系统性能。
因此,我们需要一种方法实时得监控死锁,一旦有死锁,发邮件通知我们,然后由相关人去解决。
扩展事件是一种轻量级的调优工具,占用资源少,高配置性,高扩展性。
所以我们选择用扩展事件监控死锁,然后通过警报,实时得通知我们。
备注:本实验是以自己本地数据库实例做的。
CREATE EVENTSESSIONMONITORING_DEADLOCK ONSERVER
ADD EVENTsqlserver.xml_deadlock_report
(
ACTION(sqlos.worker_address,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.client_pid,sqlserver.database_id,sqlserver.database_name,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.session_nt_username,sqlserver.sql_text,sqlserver.username)
)
ADD TARGETpackage0.ring_buffer
WITH (MAX_DISPATCH_LATENCY= 30SECONDS);
--启动该事件会话
ALTER EVENTSESSIONMONITORING_DEADLOCKONSERVERSTATE=START;
GO
--设置’在服务器启动时启动事件会话‘
(如果服务器重启的话,事件会话默认不启动,这样就查看不了会话目标信息了,因此要进行该设置)。
展开’对象资源管理器‘->管理->会话->右击该事件会话,点击’属性‘,如图:
勾选’在服务器启动时启动事件会话‘,如图:
--备注:如果服务器重启过的话,之前发生过的死锁信息就看不到了。
--删会话
--DROP EVENT SESSION MONITORING_DEADLOCK ON SERVER
在‘对象资源管理器’中,展开‘SQL SERVER代理’,右击‘警报’->‘新建警报’,如图:
--当死锁数量大于0(即出现死锁)时,发出警报。
选择‘操作员’(若没有现成的‘操作员’,则新建一个,这里之前已经建过一个操作员v-baidd),
在‘要发送的其他通知信息’处自定义信息,如:
若之前已经设置过警报管理的‘数据库配置文件’,则忽略此步骤。
若第一次建警报的话,需要设置SQL SERVER代理。
右击‘SQL SERVER代理’-‘属性’,
在‘警报’选项卡处,勾选‘启用邮件配置文件’,选择要使用的‘邮件配置文件’(这里选择了Profile1)
重启SQL SERVER代理服务
--在其中一个窗口输入并执行:
BEGIN TRAN--ROLLBACK
USE TEST;
UPDATE EMP2
SET ename='JIAOJIAO'
WHERE empno=2
WAITFOR DELAY'0:0:25';
UPDATE EMP2
SET ename='SONGSONG'
WHERE empno=4
--SELECT @@SPID 57
--在另一个窗口输入并执行:
BEGIN TRAN--ROLLBACK
USE TEST;
UPDATE EMP2
SET ename='SONGSONG'
WHERE empno=4
WAITFOR DELAY'0:0:25';
UPDATE EMP2
SET ename='JIAOJIAO'
WHERE empno=2
--SELECT @@SPID 60
就会报这样的错误:
(1 行受影响)
消息 1205,级别 13,状态 51,第 8 行
事务(进程 ID 60)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。
如图:
SELECT CAST(target_dataASXML)
FROM SYS.DM_XE_SESSIONSA
INNERJOIN SYS.dm_xe_session_targetsSONA.address=S.event_session_address
WHERE A.name='MONITORING_DEADLOCK'
点击该查询结果,能看到数据库,事务,进程,会话, SQL语句等信息。
XML文档内容如下:
<RingBufferTargettruncated="0"processingTime="0"totalEventsProcessed="2"eventCount="2"droppedCount="0"memoryUsed="16226">
<eventname="xml_deadlock_report"package="sqlserver"timestamp="2014-05-24T04:09:47.636Z">
<dataname="xml_report">
<typename="xml"package="package0" />
<value>
<deadlock>
<victim-list>
<victimProcessid="process363404188" />
</victim-list>
<process-list>
<processid="process363404188"taskpriority="0"logused="144"waitresource="KEY: 7:72057594050510848 (9d6bf8154a2a)"waittime="4064"ownerId="1841133"transactionname="user_transaction"lasttranstarted="2014-05-24T12:09:18.567"XDES="0x36a4dcd28"lockMode="X"schedulerid="4"kpid="10220"status="suspended"spid="60"sbid="0"ecid="0"priority="0"trancount="2"lastbatchstarted="2014-05-24T12:09:18.567"lastbatchcompleted="2014-05-24T12:09:13.383"lastattention="1900-01-01T00:00:00.383"clientapp="Microsoft SQL ServerManagement Studio - 查询"hostname="ZB-BAIDD-PC"hostpid="4632"loginname="SINOOCEANLAND\v-baidd"isolationlevel="read committed (2)"xactid="1841133"currentdb="7"lockTimeout="4294967295"clientoption1="671090784"clientoption2="390200">
<executionStack>
<frameprocname="adhoc"line="8"stmtstart="58"sqlhandle="0x02000000d9418b10cbc871e6336b29994a63088a4ca33f5e0000000000000000000000000000000000000000">
UPDATE [EMP2] set [ename] = @1 WHERE [empno]=@2 </frame>
<frameprocname="adhoc"line="8"stmtstart="224"sqlhandle="0x02000000b8a0b81a9a3ca4a2a3b0ea4046ed4858dfe471100000000000000000000000000000000000000000">
UPDATE EMP2
SET ename='JIAOJIAO'
WHERE empno=2
--SELECT @@SPID 60 </frame>
</executionStack>
<inputbuf>
BEGIN TRAN --ROLLBACK
USE TEST;
UPDATE EMP2
SET ename='SONGSONG'
WHERE empno=4
WAITFOR DELAY '0:0:25';
UPDATE EMP2
SET ename='JIAOJIAO'
WHERE empno=2
--SELECT @@SPID 60
</inputbuf>
</process>
<processid="process37567e558"taskpriority="0"logused="332"waitresource="KEY: 7:72057594050510848 (1a39e6095155)"waittime="5553"ownerId="1841125"transactionname="user_transaction"lasttranstarted="2014-05-24T12:09:17.077"XDES="0x366901048"lockMode="X"schedulerid="4"kpid="11312"status="suspended"spid="57"sbid="0"ecid="0"priority="0"trancount="2"lastbatchstarted="2014-05-24T12:09:17.077"lastbatchcompleted="2014-05-24T12:09:15.673"lastattention="1900-01-01T00:00:00.673"clientapp="Microsoft SQL ServerManagement Studio - 查询"hostname="ZB-BAIDD-PC"hostpid="4632"loginname="SINOOCEANLAND\v-baidd"isolationlevel="read committed (2)"xactid="1841125"currentdb="7"lockTimeout="4294967295"clientoption1="671090784"clientoption2="390200">
<executionStack>
<frameprocname="adhoc"line="8"stmtstart="58"sqlhandle="0x02000000d9418b10cbc871e6336b29994a63088a4ca33f5e0000000000000000000000000000000000000000">
UPDATE [EMP2] set [ename] = @1 WHERE [empno]=@2 </frame>
<frameprocname="adhoc"line="8"stmtstart="254"sqlhandle="0x02000000f5add204ea99c109e6338086d7a147bf252cb5560000000000000000000000000000000000000000">
UPDATE EMP2
SET ename='SONGSONG'
WHERE empno=4
--SELECT @@SPID 57 </frame>
</executionStack>
<inputbuf>
--在其中一个窗口输入并执行:
BEGIN TRAN --ROLLBACK
USE TEST;
UPDATE EMP2
SET ename='JIAOJIAO'
WHERE empno=2
WAITFOR DELAY '0:0:25';
UPDATE EMP2
SET ename='SONGSONG'
WHERE empno=4
--SELECT @@SPID 57
</inputbuf>
</process>
</process-list>
<resource-list>
<keylockhobtid="72057594050510848"dbid="7"objectname="test.dbo.EMP2"indexname="1"id="lock37ab45580"mode="X"associatedObjectId="72057594050510848">
<owner-list>
<ownerid="process37567e558"mode="X" />
</owner-list>
<waiter-list>
<waiterid="process363404188"mode="X"requestType="wait" />
</waiter-list>
</keylock>
<keylockhobtid="72057594050510848"dbid="7"objectname="test.dbo.EMP2"indexname="1"id="lock37ab44780"mode="X"associatedObjectId="72057594050510848">
<owner-list>
<ownerid="process363404188"mode="X" />
</owner-list>
<waiter-list>
<waiterid="process37567e558"mode="X"requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</value>
</data>
<actionname="username"package="sqlserver">
<typename="unicode_string"package="package0" />
<value>sa</value>
</action>
<actionname="session_nt_username"package="sqlserver">
<typename="unicode_string"package="package0" />
<value />
</action>
<actionname="session_id"package="sqlserver">
<typename="uint16"package="package0" />
<value>18</value>
</action>
<actionname="query_plan_hash"package="sqlserver">
<typename="uint64"package="package0" />
<value>0</value>
</action>
<actionname="database_name"package="sqlserver">
<typename="unicode_string"package="package0" />
<value>master</value>
</action>
<actionname="database_id"package="sqlserver">
<typename="uint16"package="package0" />
<value>1</value>
</action>
<actionname="client_pid"package="sqlserver">
<typename="uint32"package="package0" />
<value>0</value>
</action>
<actionname="client_hostname"package="sqlserver">
<typename="unicode_string"package="package0" />
<value />
</action>
<actionname="client_app_name"package="sqlserver">
<typename="unicode_string"package="package0" />
<value />
</action>
<actionname="worker_address"package="sqlos">
<typename="ptr"package="package0" />
<value>0x0000000365b94160</value>
</action>
</event>
</RingBufferTarget>
USE DBA;
GO
CREATE VIEW Perfermance.v_find_deadlock_1
(
时间戳,
SQL语句,
主机名称,
登录名称,
客户端应用程序,
进程号,
当前数据库,
状态,
等待时间 ,
kpid,
锁模式,
等待资源 ,
事务隔离级别
)
AS
--一造成死锁的系列信息
SELECT node.event_data.value('(@timestamp)[1]','Datetime')AS时间戳,--小时,分钟不对,只能大概了解日期跟发生的先后顺序
node.event_data.value('(data/value/deadlock/process-list/process/inputbuf)[2]','NVARCHAR(MAX)')ASSQL语句,
node.event_data.value('(data/value/deadlock/process-list/process/@hostname)[2]','nvarchar(100)')AS主机名称,
node.event_data.value('(data/value/deadlock/process-list/process/@loginname)[2]','nvarchar(100)')AS登录名称,
node.event_data.value('(data/value/deadlock/process-list/process/@clientapp)[2]','nvarchar(200)')AS客户端应用程序,
node.event_data.value('(data/value/deadlock/process-list/process/@spid)[2]','nvarchar(100)')AS进程号,
node.event_data.value('(data/value/deadlock/process-list/process/@currentdb)[2]','nvarchar(200)')AS当前数据库,
node.event_data.value('(data/value/deadlock/process-list/process/@status)[2]','nvarchar(200)')AS状态,
node.event_data.value('(data/value/deadlock/process-list/process/@waittime)[2]','nvarchar(200)')AS等待时间,
node.event_data.value('(data/value/deadlock/process-list/process/@kpid)[2]','nvarchar(200)')ASkpid,
node.event_data.value('(data/value/deadlock/process-list/process/@lockMode)[2]','nvarchar(200)')AS锁模式,
node.event_data.value('(data/value/deadlock/process-list/process/@waitresource)[2]','nvarchar(200)')AS等待资源,
node.event_data.value('(data/value/deadlock/process-list/process/@isolationlevel)[2]','nvarchar(200)')AS事务隔离级别
--
FROM
(SELECTCAST(T.TARGET_DATAASXML)AStarget_data
FROM SYS.dm_xe_sessionsS
INNER JOIN SYS.DM_XE_SESSION_TARGETSTONS.address=T.event_session_address
WHERE S.name='MONITORING_DEADLOCK'
)AS T
CROSSAPPLYT.target_data.nodes('//RingBufferTarget/event')ASnode(event_data)
USE DBA;
GO
CREATE VIEW Perfermance.v_find_deadlock_2
(
时间戳,
SQL语句,
主机名称,
登录名称,
客户端应用程序,
进程号,
当前数据库,
状态,
等待时间 ,
kpid,
锁模式,
等待资源 ,
事务隔离级别
)
AS
SELECT node.event_data.value('(@timestamp)[1]','Datetime')AS时间戳,--小时,分钟不对,只能大概了解日期跟发生的先后顺序
node.event_data.value('(data/value/deadlock/process-list/process/inputbuf)[1]','NVARCHAR(MAX)')ASSQL语句,
node.event_data.value('(data/value/deadlock/process-list/process/@hostname)[1]','nvarchar(100)')AS造成死锁所在主机名称,
node.event_data.value('(data/value/deadlock/process-list/process/@loginname)[1]','nvarchar(100)')AS登录名称,
node.event_data.value('(data/value/deadlock/process-list/process/@clientapp)[1]','nvarchar(200)')AS客户端登录程序,
node.event_data.value('(data/value/deadlock/process-list/process/@spid)[1]','nvarchar(100)')AS进程号,
node.event_data.value('(data/value/deadlock/process-list/process/@currentdb)[1]','nvarchar(200)')AS当前数据库,
node.event_data.value('(data/value/deadlock/process-list/process/@status)[1]','nvarchar(200)')AS状态,
node.event_data.value('(data/value/deadlock/process-list/process/@waittime)[1]','nvarchar(200)')AS等待时间,
node.event_data.value('(data/value/deadlock/process-list/process/@kpid)[1]','nvarchar(200)')ASkpid,
node.event_data.value('(data/value/deadlock/process-list/process/@lockMode)[1]','nvarchar(200)')AS锁模式,
node.event_data.value('(data/value/deadlock/process-list/process/@waitresource)[1]','nvarchar(200)')AS等待资源,
node.event_data.value('(data/value/deadlock/process-list/process/@isolationlevel)[1]','nvarchar(200)')AS事务隔离级别
--
FROM
(SELECTCAST(T.TARGET_DATAASXML)AStarget_data
FROM SYS.dm_xe_sessionsS
INNER JOIN SYS.DM_XE_SESSION_TARGETSTONS.address=T.event_session_address
WHERE S.name='MONITORING_DEADLOCK'
)AS T
CROSSAPPLYT.target_data.nodes('//RingBufferTarget/event')ASnode(event_data)
USE DBA;
SELECT *
FROM v_find_deadlock_2
--有必要的话,可以加WHERE条件过滤信息。
USE DBA;
SELECT *
FROM v_find_deadlock_1
--有必要的话,可以加WHERE条件过滤信息。
结果如图:
--注意:这个时间戳是由timestamp数据类型转换成日期类型的,日期是正确的,但是时分秒不准确。