교착 상태가 발생하는 상황이 있는데 범인을 좁힌 것으로 생각되지만 문제를 해결하기 위해 어떻게해야할지 잘 모르겠습니다.
이것은 SQL Server 2008 R2를 실행하는 프로덕션 환경에 있습니다.
상황에 대해 약간 단순화 된보기를 제공하려면 다음을 수행하십시오.
아래 정의 된 3 개의 테이블이 있습니다.
TABLE activity (
id, -- PK
...
)
TABLE member_activity (
member_id, -- PK col 1
activity_id, -- PK col 2
...
)
TABLE follow (
id, -- PK
follower_id,
member_id,
...
)
member_activity
테이블은 기본 키가 정의 화합물을 가지고 member_id, activity_id
나는 오직 그 테이블 방식으로 그 데이터를 검색해야하기 때문에.
또한 클러스터되지 않은 인덱스가 있습니다 follow
.
CREATE NONCLUSTERED INDEX [IX_follow_member_id_includes]
ON follow ( member_id ASC ) INCLUDE ( follower_id )
또한 network_activity
다음과 같이 정의 된 스키마 바운드 뷰 가 있습니다.
CREATE VIEW network_activity
WITH SCHEMABINDING
AS
SELECT
follow.follower_id as member_id,
member_activity.activity_id as activity_id,
COUNT_BIG(*) AS cb
FROM member_activity
INNER JOIN follow ON follow.member_id = member_activity.member_id
INNER JOIN activity ON activity.id = member_activity.activity_id
GROUP BY follow.follower_id, member_activity.activity_id
고유 한 클러스터형 인덱스도 있습니다.
CREATE UNIQUE CLUSTERED INDEX [IX_network_activity_unique_member_id_activity_id]
ON network_activity
(
member_id ASC,
activity_id ASC
)
이제 두 개의 교착 상태 저장 프로 시저가 있습니다. 그들은 다음 과정을 거칩니다 :
-- SP1: insert activity
-----------------------
INSERT INTO activity (...)
SELECT ... FROM member_activity WHERE member_id = @a AND activity_id = @b
INSERT INTO member_activity (...)
-- SP2: insert follow
---------------------
SELECT follow WHERE member_id = @x AND follower_id = @y
INSERT INTO follow (...)
이 두 절차는 모두 READ COMMITTED 격리에서 실행됩니다. 1222 확장 이벤트 출력을 쿼리하고 교착 상태와 관련하여 다음을 해석했습니다.
SP2가 충돌하는 (X) 잠금을 유지하는 동안 SP1
RangeS-S
이IX_follow_member_id_includes
인덱스 에서 키 잠금을 기다리고 있습니다.SP1이 충돌하는 (X) 잠금을 유지하는 동안 SP2가
S
모드 잠금을 대기 중입니다.PK_member_activity
교착 상태는 각 쿼리의 마지막 줄 (삽입)에서 발생하는 것으로 보입니다. SP1이 IX_follow-member_id_includes
인덱스 에 대한 잠금을 원하는 이유는 분명하지 않습니다 . 나에게 유일한 링크는이 색인보기에서 나온 것으로 보이므로 내가 포함 시켰습니다.
이러한 교착 상태가 발생하지 않도록하는 가장 좋은 방법은 무엇입니까? 도움을 주시면 감사하겠습니다. 교착 상태 문제를 해결 한 경험이 많지 않습니다.
도움이 될만한 더 많은 정보가 있으면 알려주세요!
미리 감사드립니다.
편집 1 : 요청마다 정보를 추가하십시오.
이 교착 상태의 1222 출력은 다음과 같습니다.
<deadlock>
<victim-list>
<victimProcess id="process4c6672748" />
</victim-list>
<process-list>
<process id="process4c6672748" taskpriority="0" logused="332" waitresource="KEY: 8:72057594104905728 (25014f77eaba)" waittime="581" ownerId="474698706" transactionname="INSERT" lasttranstarted="2014-07-03T17:03:12.287" XDES="0x298487970" lockMode="RangeS-S" schedulerid="1" kpid="972" status="suspended" spid="79" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-07-03T17:03:12.283" lastbatchcompleted="2014-07-03T17:03:12.283" lastattention="2014-07-03T10:25:00.283" clientapp=".Net SqlClient Data Provider" hostname="WIN08CLYDESDALE" hostpid="4596" loginname="TechPro" isolationlevel="read committed (2)" xactid="474698706" currentdb="8" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="" line="7" stmtstart="1194" stmtend="1434" sqlhandle="0x02000000a26bb72a2b220406876cad09c22242e5265c82e6" />
<frame procname="" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000" />
</executionStack>
<inputbuf> <!-- SP 1 --> </inputbuf>
</process>
<process id="process6cddc5b88" taskpriority="0" logused="456" waitresource="KEY: 8:72057594098679808 (89013169fc76)" waittime="567" ownerId="474698698" transactionname="INSERT" lasttranstarted="2014-07-03T17:03:12.283" XDES="0x30c459970" lockMode="S" schedulerid="4" kpid="4204" status="suspended" spid="70" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-07-03T17:03:12.283" lastbatchcompleted="2014-07-03T17:03:12.283" lastattention="2014-07-03T15:04:55.870" clientapp=".Net SqlClient Data Provider" hostname="WIN08CLYDESDALE" hostpid="4596" loginname="TechPro" isolationlevel="read committed (2)" xactid="474698698" currentdb="8" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="" line="18" stmtstart="942" stmtend="1250" sqlhandle="0x03000800ca458d315ee9130100a300000100000000000000" />
</executionStack>
<inputbuf> <!-- SP 2 --> </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594104905728" dbid="8" objectname="" indexname="" id="lock33299fc00" mode="X" associatedObjectId="72057594104905728">
<owner-list>
<owner id="process6cddc5b88" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process4c6672748" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594098679808" dbid="8" objectname="" indexname="" id="lockb7e2ba80" mode="X" associatedObjectId="72057594098679808">
<owner-list>
<owner id="process4c6672748" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process6cddc5b88" mode="S" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
이 경우
associatedObjectId 72057594098679808는 member_activity, PK_member_activity
associatedObjectId 72057594104905728가 follow, IX_follow_member_id_includes
또한 SP1 및 SP2의 기능에 대한보다 정확한 그림이 있습니다.
-- SP1: insert activity
-----------------------
DECLARE @activityId INT
INSERT INTO activity (field1, field2)
VALUES (@field1, @field2)
SET @activityId = SCOPE_IDENTITY();
IF NOT EXISTS(
SELECT TOP 1 member_id
FROM member_activity
WHERE member_id = @m1 AND activity_id = @activityId
)
INSERT INTO member_activity (member_id, activity_id, field1)
VALUES (@m1, @activityId, @field1)
IF NOT EXISTS(
SELECT TOP 1 member_id
FROM member_activity
WHERE member_id = @m2 AND activity_id = @activityId
)
INSERT INTO member_activity (member_id, activity_id, field1)
VALUES (@m2, @activityId, @field1)
SP2도 :
-- SP2: insert follow
---------------------
IF NOT EXISTS(
SELECT TOP 1 1
FROM follow
WHERE member_id = @memberId AND follower_id = @followerId
)
INSERT INTO follow (member_id, follower_id)
VALUES (@memberId, @followerId)
편집 2 : 주석을 다시 읽은 후 외래 키 열에 대한 정보를 추가 할 것이라고 생각했습니다 ...
member_activity.member_id
member
테이블 의 외래 키입니다member_activity.activity_id
activity
테이블 의 외래 키입니다follow.member_id
member
테이블 의 외래 키입니다follow.follower_id
member
테이블 의 외래 키입니다
업데이트 1 :
나는 교착 상태를 예방하는 데 도움이 될만한 몇 가지 변경 사항을 운없이 내 렸습니다.
내가 변경 한 내용은 다음과 같습니다.
-- SP1: insert activity
-----------------------
DECLARE @activityId INT
INSERT INTO activity (field1, field2)
VALUES (@field1, @field2)
SET @activityId = SCOPE_IDENTITY();
MERGE member_activity WITH ( HOLDLOCK ) as target
USING (SELECT @m1 as member_id, @activityId as activity_id, @field1 as field1) as source
ON target.member_id = source.member_id
AND target.activity_id = source.activity_id
WHEN NOT MATCHED THEN
INSERT (member_id, activity_id, field1)
VALUES (source.member_id, source.activity_id, source.field1)
;
MERGE member_activity WITH ( HOLDLOCK ) as target
USING (SELECT @m2 as member_id, @activityId as activity_id, @field1 as field1) as source
ON target.member_id = source.member_id
AND target.activity_id = source.activity_id
WHEN NOT MATCHED THEN
INSERT (member_id, activity_id, field1)
VALUES (source.member_id, source.activity_id, source.field1)
;
SP2의 경우 :
-- SP2: insert follow
---------------------
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION
IF NOT EXISTS(
SELECT TOP 1 1
FROM follow WITH ( UPDLOCK )
WHERE member_id = @memberId AND follower_id = @followerId
)
INSERT INTO follow (member_id, follower_id)
VALUES (@memberId, @followerId)
COMMIT
이 두 가지 변경으로 여전히 교착 상태가 발생하는 것 같습니다.
제공 할 수있는 다른 것이 있으면 알려주세요. 감사.
SERIALIZABLE
(그것보다 조금 더 있지만 응답이 아닙니다 :)