2017-03-20 5 views
1

각 시스템 데이터베이스에 추가 매개 변수없이 dbcc checkdb 문을 실행하는 매일 작업이 있습니다. 이 작업은 사용량이 적은 시간에 실행되며 일반적으로 실행하는 데 5 초 이하가 소요됩니다.시스템 데이터베이스의 dbcc checkdb와 사용자 데이터베이스의 sp_executesql이 교착 상태를 일으키는 이유는 무엇입니까?

그러나 마지막 실행은 단지 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\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> 

솔루션 난 임시 데이터베이스에 대한 매일 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]; 
+0

@ TheGameiswar가 제공 한 답변에 이어 다음과 같이 구현 한 솔루션도 게시하고 있습니다. 여전히 tempdb를 확인하고 있지만 이제 교착 상태 우선 순위가 낮은 프로 시저를 제공합니다. 사용자 트랜잭션은 일별 시스템 검사, 특히 tempdb의 우선 순위에 따라 우선 순위를 지정해야한다는 아이디어가 있습니다. 이와 같은 교착 상태 시나리오가 산발적으로 발생하는 것만으로도 가능한 선택 인 것으로 보입니다. –

답변

0

왜 사용자 데이터베이스에 시스템 데이터베이스와 sp_executesql을에 DBCC CHECKDB는 교착 상태가 발생할 수 있습니까?

DBCC CHECKDB는 tempdb.sys.sysrowsets에 의도 배타 잠금을 획득하고

사용자 PROC

는 또한 TEMPDB resources.This 사용자 시저에 액세스하고 .. tempdb.sys.sysrscols에 sharedlock을 기다리고 tempdb.sys.sysrscols에 IX 잠금을 획득 와 .. tempdb.sys.sysrowsets에 공유 락을 대기

따라서 교착 상태가 발생하고이

일반적으로는, DBCC CHECKDB 분석하기 전에 데이터베이스의 스냅 샷을 교착 상태의 간단한 경우이며 작동합니다 잠금을 피하기 위해이 스냅 샷에.

이 경우에는 as per this post .. 스냅 샷을 TEMPDB에서 사용할 수 없으므로 두 가지 트랜잭션에서 획득 한 호환되지 않는 잠금이 있으므로 교착 상태의 원인이됩니다. 당신은 보았다.

+0

답변 주셔서 감사합니다 @ TheGameiswar. 그것은 당신이 말했듯이 tempdb가이 교착 상태의 중간에 있다는 것을 완벽하게 이해합니다. dbcc checkdb 문이 스냅 샷을 생성하지만 tempdb 예외가 간과된다는 가정하에있었습니다. –