오늘 우리는 나를 매우 신비하게 만드는 매우 흥미로운 사례가있었습니다. 한 마디로 우리는 리팩터링을 반복하여 반복 코드에서 트리거를 정리하여 단일 및 재사용 가능한 저장 프로 시저로 추출했습니다. 이 리팩터링은 부작용이 없을 것이라고 생각했지만 잘못되었습니다. 릴리스 이후에 우리는 분명한 이유없이 많은 교착 상태와 성능 저하를 경험했습니다. 시스템 테이블을 검사하여 어떤 DB를 가져 왔는지 확인한 결과 위의 리팩토링과 관련되어 있다는 것을 알았고 업데이트를 롤백하는 것으로 끝 맺었습니다.트리거의 일부를 저장 프로 시저로 추출한 후 교착 상태가 발생했습니다.
아직 테스트를 검증하기 위해 테스트 환경에서 문제를 재현하지 않았으므로 문제가 표시 될 수 있도록 약간의 까다로운 조건이 발생합니다.
다음은 변경 사항에 대한 세부 정보입니다. 우리는 많은 트리거를 업데이트했지만 모두 비슷합니다. 내가 보여줄 것입니다. 두 개의 프로세스가 단일 트리거 (아래 보여주기)를 실행하고 교착 상태가 발생하는 교착 상태가 있음을 보여주는 교착 상태 그래프를 발견 했으므로 충분해야합니다.
이전에 작동했던 솔루션부터 시작해 보겠습니다. (다시 살펴보면 아래 표시된 교착 상태 해결 방법과 거의 동일합니다.)
CREATE TRIGGER [dbo].[TR__xyz__update_sync_publishers]
ON [dbo].[xyz]
AFTER INSERT, DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON;
if(TRIGGER_NESTLEVEL() = 1)
BEGIN
create table #AffectedIDs (advisor_id int primary key)
insert into #AffectedIDs
select distinct t.id
from
(select id
from inserted
inner join xyz a ON a.id = id
where [text] <> ''
union
select id
from inserted
inner join xyz a ON a.id = id
where [text] <> '') t
declare @date datetime = getutcdate()
declare @RegisteredObjectTypeID int = 2
declare @SyncPublisherSourceID int = 1
update pub
set pub.master_update_date = @date
from #AffectedIDs affected
inner join sync_publishers pub on
pub.sync_registered_object_type_id = @RegisteredObjectTypeID
and pub.sync_publisher_source_id = @SyncPublisherSourceID
and pub.sync_object_id = affected.advisor_id
insert into sync_publishers (sync_object_id, sync_registered_object_type_id, sync_publisher_source_id , master_update_date)
select
affected.advisor_id,
@RegisteredObjectTypeID,
@SyncPublisherSourceID,
@date
from #AffectedIDs affected
left join sync_publishers pub on
pub.sync_registered_object_type_id = @RegisteredObjectTypeID
and pub.sync_publisher_source_id = @SyncPublisherSourceID
and pub.sync_object_id = affected.advisor_id
where
pub.sync_object_id is null
drop table #AffectedIDs
END
END
여기 교착 상태가되는 새로운 트리거가 있습니다. dtInt의
CREATE PROCEDURE [dbo].[SyncTracker_PublishEvent]
@objectTypeId int,
@ids dtInt readonly
AS
BEGIN
SET NOCOUNT ON;
if(TRIGGER_NESTLEVEL() > 1) RETURN;
declare @pubSourceId int = 1
declare @date datetime = getutcdate()
update pub
set pub.master_update_date = @date
from @ids affected
inner join sync_publishers pub
on pub.sync_registered_object_type_id = @objectTypeId
and pub.sync_publisher_source_id = @pubSourceId
and pub.sync_object_id = affected.value
insert into sync_publishers (sync_object_id, sync_registered_object_type_id, sync_publisher_source_id , master_update_date)
select affected.value, @objectTypeId, @pubSourceId, @date
from @ids affected
left join sync_publishers pub
on pub.sync_registered_object_type_id = @objectTypeId
and pub.sync_publisher_source_id = @pubSourceId
and pub.sync_object_id = affected.value
where
pub.sync_object_id is null
END
GO
정의 : 여기
CREATE TRIGGER [dbo].[TR__xyz__update_sync_publishers]
ON [dbo].[xyz]
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
SET NOCOUNT ON;
declare @ids dtInt
insert into @ids
select distinct t.id
from
(
select id from inserted
INNER JOIN xyz a ON a.id = id
WHERE [text] <> ''
union
select id from inserted
INNER JOIN xyz a ON a.id = id
WHERE [text] <> ''
) t
exec SyncTracker_PublishEvent 2, @ids
END
추출 SP의 정의이다.
CREATE TYPE [dbo].[dtInt] AS TABLE
(
[value] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
[value] ASC
)
)
그리고 마지막으로 교착 상태 그래프.
<deadlock>
<victim-list>
<victimProcess id="processe1892fe8c8" />
</victim-list>
<process-list>
<process id="processe1892fe8c8" taskpriority="0" logused="3824" waitresource="KEY: 5:72057602924150784 (4776e78e2961)" waittime="5686" ownerId="2583257965" transactionname="user_transaction" lasttranstarted="2016-10-03T08:30:42.500" XDES="0xe192b24408" lockMode="U" schedulerid="6" kpid="41296" status="suspended" spid="141" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-10-03T08:30:42.503" lastbatchcompleted="2016-10-03T08:30:42.493" lastattention="2016-10-03T08:29:01.693" clientapp="..." hostname="..." hostpid="22572" loginname="kbuser" isolationlevel="read committed (2)" xactid="2583257965" currentdb="5" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
<executionStack>
<frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.SyncTracker_PublishEvent" line="21" stmtstart="1178" stmtend="1680" sqlhandle="0x030005007bf23c4b5012b40092a6000001000000000000000000000000000000000000000000000000000000">
update pub
set pub.master_update_date = @date
from @ids affected
inner join sync_publishers pub
on pub.sync_registered_object_type_id = @objectTypeId
and pub.sync_publisher_source_id = @pubSourceId
and pub.sync_object_id = affected.valu </frame>
<frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.TR__xyz__update_sync_publishers" line="28" stmtstart="1300" stmtend="1372" sqlhandle="0x03000500f711233ddee4c60090a6000000000000000000000000000000000000000000000000000000000000">
exec SyncTracker_PublishEvent 2, @id </frame>
<frame procname="unknown" line="1" stmtstart="1054" stmtend="3032" sqlhandle="0x02000000912653235c5ef3529289f19ae4445e62ee1ccbc00000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
</process>
<process id="processdfa401b848" taskpriority="0" logused="9384" waitresource="KEY: 5:72057602924150784 (1501093f83b4)" waittime="5814" ownerId="2582414029" transactionname="user_transaction" lasttranstarted="2016-10-03T08:30:09.933" XDES="0x104486ac408" lockMode="U" schedulerid="1" kpid="19548" status="suspended" spid="213" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-10-03T08:30:53.047" lastbatchcompleted="2016-10-03T08:30:53.047" lastattention="1900-01-01T00:00:00.047" clientapp="..." hostname="..." hostpid="6196" loginname="kbuser" isolationlevel="read committed (2)" xactid="2582414029" currentdb="5" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
<executionStack>
<frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.SyncTracker_PublishEvent" line="21" stmtstart="1178" stmtend="1680" sqlhandle="0x030005007bf23c4b5012b40092a6000001000000000000000000000000000000000000000000000000000000">
update pub
set pub.master_update_date = @date
from @ids affected
inner join sync_publishers pub
on pub.sync_registered_object_type_id = @objectTypeId
and pub.sync_publisher_source_id = @pubSourceId
and pub.sync_object_id = affected.valu </frame>
<frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.TR__xyz__update_sync_publishers" line="28" stmtstart="1300" stmtend="1372" sqlhandle="0x03000500f711233ddee4c60090a6000000000000000000000000000000000000000000000000000000000000">
exec SyncTracker_PublishEvent 2, @id </frame>
<frame procname="unknown" line="1" stmtstart="1120" stmtend="3132" sqlhandle="0x020000007414d821ed68a2ab4462b4eca6b2fdb4ba28cc350000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057602924150784" dbid="5" objectname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.sync_publishers" indexname="IX__sync_publishers__registered_object_type_id__sync_object_id" id="lock10887a96b00" mode="X" associatedObjectId="72057602924150784">
<owner-list>
<owner id="processdfa401b848" mode="X" />
</owner-list>
<waiter-list>
<waiter id="processe1892fe8c8" mode="U" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057602924150784" dbid="5" objectname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.sync_publishers" indexname="IX__sync_publishers__registered_object_type_id__sync_object_id" id="lockdb7d7b8200" mode="X" associatedObjectId="72057602924150784">
<owner-list>
<owner id="processe1892fe8c8" mode="X" />
</owner-list>
<waiter-list>
<waiter id="processdfa401b848" mode="U" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
여기에 해당 sync_publishers의 정의
: http://pastebin.com/LviwwCDi.실현 가능한 원인에 대한 의견이 있으시면 - 공유 하시길 바랍니다 - 매우 감사하겠습니다!
UPDATE UPDATE 1. 실제 실행 계획/sync_publishers
실제 실행 계획에 삽입은 동일 꽤 많이 보인다.
이전 실행 계획 (해당하지 않음).
가 아닌 내
sync_publisher_source_id
누락으로 인해 쿼리 계획에서 "키 조회"를 제거 당함 :UPDATE 2. 시도 일부는
이 좀 오늘 조언 시도 않았다 조언 클러스터 된 인덱스를 완전히 삭제 컬럼 - 우리의 구현에 정말 필수 아니었다.
UPDATE + INSERT
을 하나의MERGE
문으로 수정했습니다.MERGE sync_publishers2 t USING @ids s ON s.[value] = t.sync_object_id and t.sync_registered_object_type_id = @objectTypeId WHEN MATCHED THEN UPDATE SET master_update_date = @date WHEN NOT MATCHED THEN INSERT (sync_object_id, sync_registered_object_type_id, master_update_date) VALUES (s.[value], @objectTypeId, @date);
MERGE
제표에 교착 상태를 시작. 새로운 데드락 그래프는 여기에서 볼 수 있습니다 : http://pastebin.com/QNJk7tea. 하지만 행운과 함께 - -
UPDATE 3. 시도 MERGE는
나는 xlock
및 holdlock
힌트 MERGE
을 시도한 힌트 다시 MERGE에 교착 상태를 얻었다.
MERGE sync_publishers2 with(xlock, holdlock) t
트리거 본문에 TRIGGER_NESTLEVEL()를 확인하십시오. proc 버전에서는이 코드가 두 번 실행될 수 있습니다 :'insert into @ids select t.id from()'이것은 잠금이 유지되는 기간에 심각한 영향을 미칠 수 있습니다. – Serg
"UPDATE pub"및 "INSERT INTO sync_publishers"문의 실제 실행 계획을 SP에서 트리거 대 트리거 확인하십시오. 카디널리티 예측으로 인해 다른 실행 계획을 얻고 있습니까? –
@RazvanSocol, 제안에 감사드립니다! 두 경우의 실제 실행 계획으로 게시물을 업데이트했습니다. 거의 동일하게 보입니다 ... –