Ich habe einen täglichen Job, der eine Anweisung dbcc checkdbb ohne zusätzliche Parameter in jeder der Systemdatenbanken ausführt. Dieser Job wird außerhalb der Stoßzeiten ausgeführt und dauert in der Regel 5 Sekunden oder weniger.Warum verursachen dbcc checkdb in Systemdatenbanken und sp_executesql in einer Benutzerdatenbank einen Deadlock?
Der letzte Lauf dauerte jedoch nur 1 Sekunde und scheiterte an einem Deadlock. Ich habe eine Warnung erhalten, die mir eine XML-Grafik des Deadlocks speichert, die ich für detailliertere Informationen einschließe.
Meine Hauptfragen sind: Warum tritt solch ein Deadlock tatsächlich auf und ist es vermeidbar?
<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\0000" 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\0000" 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>
Lösung Ich habe implementiert für TempDB Benutzertransaktionen über Täglich checkdb priortize:
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];
Im Anschluss an die Antwort von @TheGameiswar posten wir auch die Lösung, die ich implementiert habe. Ich überprüfe immer noch tempdb, aber jetzt habe ich die Prozedur Ich verwende eine niedrigere Deadlock-Priorität. Die Idee ist, dass Benutzertransaktionen über eine tägliche Systemprüfung, genauer gesagt die von tempdb, priorisiert werden sollten. Da ein Deadlock-Szenario nur sporadisch auftritt, scheint es eine praktikable Alternative zu sein. –