为什么系统数据库上的 dbcc checkdb 和用户数据库上的 sp_executesql 会导致死锁?
Why do dbcc checkdb on system databases and sp_executesql on a user database cause a deadlock?
我有一份日常工作 运行在每个系统数据库上执行一个没有附加参数的 dbcc checkdb 语句。此作业在非高峰时段 运行 秒,通常需要 5 秒或更短的时间才能 运行。
然而,最后一个运行只用了1秒就因为死锁而失败了。我收到一个警报,它为我保存了一个 xml 死锁图表,我将其包括在内以获取更详细的信息。
我的主要问题是:为什么会出现这样的死锁,是否可以避免?
<TextData>
<deadlock-list>
<deadlock victim="process290fd861088">
<process-list>
<process id="process290fd861088" taskpriority="0" logused="0" waitresource="OBJECT: 2:5:0 " ownerId="1250115008" transactionname="CheckDb" lasttranstarted="2017-03-20T01:00:01.427" XDES="0x2b277040bd8" lockMode="S" schedulerid="7" kpid="12760" status="suspended" spid="78" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2017-03-20T01:00:00.060" lastbatchcompleted="2017-03-20T01:00:00.060" lastattention="1900-01-01T00:00:00.060" clientapp="SQLAgent - TSQL JobStep (Job 0xB425122DD6C28D4BBE42D7F0AF76FC40 : Step 1)" hostname="0000-DB-0000" hostpid="8040" loginname="0000[=11=]00" isolationlevel="read committed (2)" xactid="1250115008" currentdb="2" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="0000_Local.server.CheckSystemDatabases" line="19" stmtstart="740" stmtend="776" sqlhandle="0x030006006a934a11b3ebcd0023a7000001000000000000000000000000000000000000000000000000000000">
dbcc checkdb(@dbId </frame>
<frame procname="adhoc" line="1" stmtend="70" sqlhandle="0x010006006688101b405fcfceb602000000000000000000000000000000000000000000000000000000000000">
exec [server].[CheckSystemDatabases </frame>
</executionStack>
<inputbuf>
exec [server].[CheckSystemDatabases]; </inputbuf>
</process>
<process id="process2b59a715468" taskpriority="0" logused="952" waitresource="OBJECT: 2:3:0 " ownerId="1250114957" transactionname="droptemp" lasttranstarted="2017-03-20T01:00:01.423" XDES="0x29b8755ce58" lockMode="IX" schedulerid="8" kpid="9440" status="suspended" spid="67" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2017-03-20T01:00:01.410" lastbatchcompleted="2017-03-20T01:00:01.410" lastattention="1900-01-01T00:00:00.410" clientapp="0000-API-0000" hostname="0000-0000-WEB-0000" hostpid="42180" loginname="0000[=11=]00" isolationlevel="read committed (2)" xactid="0" currentdb="9" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="mssqlsystemresource.sys.sp_executesql" line="1" stmtstart="-1" sqlhandle="0x0400ff7f427f99d9010000000000000000000000000000000000000000000000000000000000000000000000">
sp_executesql </frame>
<frame procname="0000.dbo.SomeProcName" line="93" stmtstart="8320" stmtend="8496" sqlhandle="0x030009002ac137082fa8b20029a7000001000000000000000000000000000000000000000000000000000000">
exec sp_executesql @selectSql, N'@rowcount int output', @rowcount = @TotalRowCount outpu </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 9 Object Id = 137871658] </inputbuf>
</process>
</process-list>
<resource-list>
<objectlock lockPartition="0" objid="5" subresource="FULL" dbid="2" objectname="tempdb.sys.sysrowsets" id="lock2b4103b8380" mode="IX" associatedObjectId="5">
<owner-list>
<owner id="process2b59a715468" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process290fd861088" mode="S" requestType="wait" />
</waiter-list>
</objectlock>
<objectlock lockPartition="0" objid="3" subresource="FULL" dbid="2" objectname="tempdb.sys.sysrscols" id="lock291f3d8a900" mode="S" associatedObjectId="3">
<owner-list>
<owner id="process290fd861088" mode="S" />
</owner-list>
<waiter-list>
<waiter id="process2b59a715468" mode="IX" requestType="wait" />
</waiter-list>
</objectlock>
</resource-list>
</deadlock>
</deadlock-list></TextData>
我已经实施的解决方案是将用户事务优先于 TempDB 的 Daily checkDB:
set nocount on;
set deadlock_priority low;
declare @dbId int;
declare loopCheckDB cursor fast_forward
for select [d].[database_id] from [sys].[databases] as [d] where [d].[database_id] < 5
order by [d].[name]
open [loopCheckDB]
fetch next from [loopCheckDB] into @dbId;
while @@FETCH_STATUS = 0
begin dbcc checkdb(@dbId);
fetch next from [loopCheckDB] into @dbId;
end
close [loopCheckDB];
deallocate [loopCheckDB];
Why do dbcc checkdb on system databases and sp_executesql on a user database cause a deadlock?
DBCC checkDB 在 tempdb.sys.sysrowsets
上获得了 Intent Exclusive 锁,正在等待 tempdb.sys.sysrscols
..
上的共享锁
您的用户进程也在访问 TEMPDB resources.This 用户进程在 tempdb.sys.sysrscols 上获得了 IX 锁,正在等待 tempdb.sys.sysrowsets..
上的共享锁
因此发生了死锁,这是一个简单的死锁案例
通常,DBCC CheckDB 在分析之前拍摄数据库快照,并在该快照上工作以避免锁定、阻塞..
在这种情况下,as per this post..无法使用 TEMPDB 进行快照,因此在您的情况下,两个事务都获得了不兼容的锁,这就是您看到的死锁的原因。
我有一份日常工作 运行在每个系统数据库上执行一个没有附加参数的 dbcc checkdb 语句。此作业在非高峰时段 运行 秒,通常需要 5 秒或更短的时间才能 运行。
然而,最后一个运行只用了1秒就因为死锁而失败了。我收到一个警报,它为我保存了一个 xml 死锁图表,我将其包括在内以获取更详细的信息。
我的主要问题是:为什么会出现这样的死锁,是否可以避免?
<TextData>
<deadlock-list>
<deadlock victim="process290fd861088">
<process-list>
<process id="process290fd861088" taskpriority="0" logused="0" waitresource="OBJECT: 2:5:0 " ownerId="1250115008" transactionname="CheckDb" lasttranstarted="2017-03-20T01:00:01.427" XDES="0x2b277040bd8" lockMode="S" schedulerid="7" kpid="12760" status="suspended" spid="78" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2017-03-20T01:00:00.060" lastbatchcompleted="2017-03-20T01:00:00.060" lastattention="1900-01-01T00:00:00.060" clientapp="SQLAgent - TSQL JobStep (Job 0xB425122DD6C28D4BBE42D7F0AF76FC40 : Step 1)" hostname="0000-DB-0000" hostpid="8040" loginname="0000[=11=]00" isolationlevel="read committed (2)" xactid="1250115008" currentdb="2" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="0000_Local.server.CheckSystemDatabases" line="19" stmtstart="740" stmtend="776" sqlhandle="0x030006006a934a11b3ebcd0023a7000001000000000000000000000000000000000000000000000000000000">
dbcc checkdb(@dbId </frame>
<frame procname="adhoc" line="1" stmtend="70" sqlhandle="0x010006006688101b405fcfceb602000000000000000000000000000000000000000000000000000000000000">
exec [server].[CheckSystemDatabases </frame>
</executionStack>
<inputbuf>
exec [server].[CheckSystemDatabases]; </inputbuf>
</process>
<process id="process2b59a715468" taskpriority="0" logused="952" waitresource="OBJECT: 2:3:0 " ownerId="1250114957" transactionname="droptemp" lasttranstarted="2017-03-20T01:00:01.423" XDES="0x29b8755ce58" lockMode="IX" schedulerid="8" kpid="9440" status="suspended" spid="67" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2017-03-20T01:00:01.410" lastbatchcompleted="2017-03-20T01:00:01.410" lastattention="1900-01-01T00:00:00.410" clientapp="0000-API-0000" hostname="0000-0000-WEB-0000" hostpid="42180" loginname="0000[=11=]00" isolationlevel="read committed (2)" xactid="0" currentdb="9" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="mssqlsystemresource.sys.sp_executesql" line="1" stmtstart="-1" sqlhandle="0x0400ff7f427f99d9010000000000000000000000000000000000000000000000000000000000000000000000">
sp_executesql </frame>
<frame procname="0000.dbo.SomeProcName" line="93" stmtstart="8320" stmtend="8496" sqlhandle="0x030009002ac137082fa8b20029a7000001000000000000000000000000000000000000000000000000000000">
exec sp_executesql @selectSql, N'@rowcount int output', @rowcount = @TotalRowCount outpu </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 9 Object Id = 137871658] </inputbuf>
</process>
</process-list>
<resource-list>
<objectlock lockPartition="0" objid="5" subresource="FULL" dbid="2" objectname="tempdb.sys.sysrowsets" id="lock2b4103b8380" mode="IX" associatedObjectId="5">
<owner-list>
<owner id="process2b59a715468" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process290fd861088" mode="S" requestType="wait" />
</waiter-list>
</objectlock>
<objectlock lockPartition="0" objid="3" subresource="FULL" dbid="2" objectname="tempdb.sys.sysrscols" id="lock291f3d8a900" mode="S" associatedObjectId="3">
<owner-list>
<owner id="process290fd861088" mode="S" />
</owner-list>
<waiter-list>
<waiter id="process2b59a715468" mode="IX" requestType="wait" />
</waiter-list>
</objectlock>
</resource-list>
</deadlock>
</deadlock-list></TextData>
我已经实施的解决方案是将用户事务优先于 TempDB 的 Daily checkDB:
set nocount on;
set deadlock_priority low;
declare @dbId int;
declare loopCheckDB cursor fast_forward
for select [d].[database_id] from [sys].[databases] as [d] where [d].[database_id] < 5
order by [d].[name]
open [loopCheckDB]
fetch next from [loopCheckDB] into @dbId;
while @@FETCH_STATUS = 0
begin dbcc checkdb(@dbId);
fetch next from [loopCheckDB] into @dbId;
end
close [loopCheckDB];
deallocate [loopCheckDB];
Why do dbcc checkdb on system databases and sp_executesql on a user database cause a deadlock?
DBCC checkDB 在 tempdb.sys.sysrowsets
上获得了 Intent Exclusive 锁,正在等待 tempdb.sys.sysrscols
..
您的用户进程也在访问 TEMPDB resources.This 用户进程在 tempdb.sys.sysrscols 上获得了 IX 锁,正在等待 tempdb.sys.sysrowsets..
上的共享锁因此发生了死锁,这是一个简单的死锁案例
通常,DBCC CheckDB 在分析之前拍摄数据库快照,并在该快照上工作以避免锁定、阻塞..
在这种情况下,as per this post..无法使用 TEMPDB 进行快照,因此在您的情况下,两个事务都获得了不兼容的锁,这就是您看到的死锁的原因。