मेरे पास एक ऐसी स्थिति है जहां मुझे गतिरोध मिल रहा है, और मुझे लगता है कि मैंने अपराधियों को कम कर दिया है, लेकिन मुझे यकीन नहीं है कि मैं इसे ठीक करने के लिए क्या कर सकता हूं।
यह 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 अलगाव में ये 2 प्रक्रियाएं चलती हैं। मैं 1222 विस्तारित ईवेंट आउटपुट को क्वेरी करने में कामयाब रहा, और गतिरोध के संबंध में निम्नलिखित व्याख्या की है:
SP1 इंडेक्स
RangeS-S
पर एक कुंजी लॉक की प्रतीक्षा कर रहा हैIX_follow_member_id_includes
जबकि SP2 एक परस्पर विरोधी (X) लॉक रखता हैSP2 एक
S
मोड लॉक की प्रतीक्षा कर रहा है,PK_member_activity
जबकि SP1 में एक परस्पर विरोधी (X) लॉक होता है
गतिरोध प्रत्येक क्वेरी (आवेषण) की अंतिम पंक्ति पर दिखाई देता है। मेरे लिए क्या अस्पष्ट है क्यों 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>
इस मामले में,
संबद्धऑब्जेक्टआई 72057594098679808 से मेल खाती है member_activity, PK_member_activity
संबद्धऑब्जेक्टआई 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
(उस की तुलना में यह करने के लिए एक सा अधिक है, लेकिन यह एक टिप्पणी नहीं एक जवाब :) है