मेरे पास दो बहुत ही सरल सारणी हैं, चलिए उन्हें [UserData1] और [UserData2] कहते हैं। दोनों में प्राथमिक उपयोगकर्ता के रूप में [UserId] कॉलम है। मैं इन दो तालिकाओं के खिलाफ दो प्रकार के प्रश्न चला रहा हूं।शामिल तालिकाओं से चयन करते समय डेडलॉक्स से कैसे बचें?
BEGIN TRANSACTION
UPDATE [UserData1]
SET <new values>
WHERE [UserId] = @UserId
UPDATE [UserData2]
SET <new values>
WHERE [UserId] = @UserId
COMMIT TRANSACTION
समस्या यहाँ है:
SELECT <a subset of columns from both tables>
FROM [UserData1] ud1
FULL OUTER JOIN [UserData2] ud2 ON ud1.[UserId] = ud2.[UserId]
WHERE
ud1.[UserId] = @UserId OR ud2.[UserId] = @UserId
अन्य कोई लेन-देन एक विशेष उपयोगकर्ता के लिए दोनों तालिकाओं में उपयोगकर्ता डेटा अपडेट कर देता है: एक एक SELECT कथन है कि एक विशेष उपयोगकर्ता के लिए संयुक्त डेटा देता है SELECT कथन में साझा तालिका ताले प्राप्त करने का आदेश अनिश्चित है, जो SQL Server सर्वर [UserData2] से पहले [UserData2] को लॉक करने का निर्णय लेता है, जो क्लासिकल डेडलॉक स्थिति का कारण बन सकता है (और वास्तव में करता है)। इस मामले में डेडलॉक्स से बचने का सबसे अच्छा तरीका क्या होगा?
इन तालिकाओं को एक टेबल में मर्ज करें, है ना? काश यह इतना आसान था। मान लीजिए कि उन्हें अलग रखने का एक कारण है।
पढ़ा गया/नोलोक संकेत? मान लीजिए गंदे पढ़ने को बर्दाश्त नहीं किया जा सकता है।
स्नैपशॉट अलगाव स्तर? इससे समस्या हल हो जाएगी, लेकिन मुझे शामिल ओवरहेड के बारे में निश्चित नहीं है।
तो प्रश्न नीचे उबलता है: उस आदेश की गारंटी देने का कोई तरीका है जिसमें शामिल तालिकाओं पर ताले अधिग्रहण किए जाते हैं?
पहले मैंने सोचा कि यह FORCE ORDER
क्वेरी संकेत के साथ हासिल किया जा सकता है, लेकिन फिर मुझे प्रयोग से पता चला कि यह आवश्यक रूप से उस क्रम को लागू नहीं करता है जिसमें टेबल लॉक हैं। इस विशेष मामले में एक और समाधान प्रत्येक तालिका के लिए अलग-अलग चयन प्रश्न जारी करना होगा और फिर अनुप्रयोग परत में दो एक-पंक्ति रिकॉर्डसेट को गठबंधन करना होगा, लेकिन यदि मुझे कभी भी एकाधिक उपयोगकर्ताओं के लिए क्वेरी करने की आवश्यकता है, तो भी मैं सभी को प्राप्त करना पसंद करूंगा एक रिकॉर्डसेट में परिणाम।
अद्यतन: बल आदेश संकेत के बावजूद,
Deadlock encountered .... Printing deadlock information
Wait-for graph
Node:1
KEY: 17:72057594039173120 (e21762ccf3dc) CleanCnt:3 Mode:X Flags: 0x1
Grant List 1:
Owner:0x00000020F75B0480 Mode: X Flg:0x40 Ref:0 Life:02000000 SPID:72 ECID:0 XactLockInfo: 0x00000020EB13ED68
SPID: 72 ECID: 0 Statement Type: UPDATE Line #: 1
Input Buf: Language Event: (@UserId bigint,@DataColumn2 int)update
Requested by:
ResType:LockOwner Stype:'OR'Xdes:0x00000020FC98DA40 Mode: S SPID:75 BatchID:0 ECID:0 TaskProxy:(0x00000020DAB38608) Value:0xf75abbc0 Cost:(0/0)
Node:2
KEY: 17:72057594039107584 (e21762ccf3dc) CleanCnt:9 Mode:S Flags: 0x1
Grant List 1:
Owner:0x00000020EEBFE580 Mode: S Flg:0x40 Ref:1 Life:00000000 SPID:75 ECID:0 XactLockInfo: 0x00000020FC98DA80
SPID: 75 ECID: 0 Statement Type: SELECT Line #: 1
Input Buf: Language Event: (@UserId bigint)select [t].[UserId], t.[DataColumn2], t1.[DataColumn1]
Requested by:
ResType:LockOwner Stype:'OR'Xdes:0x00000020EB13ED28 Mode: X SPID:72 BatchID:0 ECID:0 TaskProxy:(0x0000001F671C6608) Value:0xf75b5400 Cost:(0/456)
Victim Resource Owner:
ResType:LockOwner Stype:'OR'Xdes:0x00000020FC98DA40 Mode: S SPID:75 BatchID:0 ECID:0 TaskProxy:(0x00000020DAB38608) Value:0xf75abbc0 Cost:(0/0)
deadlock-list
deadlock victim=process20fda2ccf8
process-list
process id=process20fda2ccf8 taskpriority=0 logused=0 waitresource=KEY: 17:72057594039173120 (e21762ccf3dc) waittime=4526 ownerId=3416711 transactionname=SELECT lasttranstarted=2013-07-11T18:42:20.943 XDES=0x20fc98da40 lockMode=S schedulerid=20 kpid=2800 status=suspended spid=75 sbid=0 ecid=0 priority=0 trancount=0 lastbatchstarted=2013-07-11T18:42:20.950 lastbatchcompleted=2013-07-11T18:42:20.950 lastattention=1900-01-01T00:00:00.950 clientapp=.Net SqlClient Data Provider hostname=hostname hostpid=27716 loginname=loginname isolationlevel=read committed (2) xactid=3416711 currentdb=17 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
executionStack
frame procname=adhoc line=1 stmtstart=36 sqlhandle=0x020000001fcbbe1423a0c65cc8411344c6040e879195af3a0000000000000000000000000000000000000000
select [t].[UserId], t.[DataColumn2], t1.[DataColumn1] from [UserData1] t1 full outer join [UserData2] t on t1.[UserId]=t.[UserId] where t.[UserId][email protected] or t1.[UserId][email protected] option (force order)
frame procname=unknown line=1 sqlhandle=0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
unknown
inputbuf
(@UserId bigint)select [t].[UserId], t.[DataColumn2], t1.[DataColumn1] from [UserData1] t1 full outer join [UserData2] t on t1.[UserId]=t.[UserId] where t.[UserId][email protected] or t1.[UserId][email protected] option (force order)
process id=process20fd055498 taskpriority=0 logused=456 waitresource=KEY: 17:72057594039107584 (e21762ccf3dc) waittime=4525 ownerId=3416764 transactionname=user_transaction lasttranstarted=2013-07-11T18:42:20.960 XDES=0x20eb13ed28 lockMode=X schedulerid=9 kpid=6024 status=suspended spid=72 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2013-07-11T18:42:20.970 lastbatchcompleted=2013-07-11T18:42:20.970 lastattention=1900-01-01T00:00:00.970 clientapp=.Net SqlClient Data Provider hostname=hostname hostpid=27716 loginname=loginname isolationlevel=read committed (2) xactid=3416764 currentdb=17 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
executionStack
frame procname=adhoc line=1 stmtstart=508 sqlhandle=0x02000000c0d74a32597ec460559a2d5dbdc92f7746cdce270000000000000000000000000000000000000000
update UserData2 set [LastModified]=getutcdate(), [DataColumn2]=[DataColumn2][email protected] where [UserId][email protected]
frame procname=unknown line=1 sqlhandle=0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
unknown
inputbuf
(@UserId bigint,@DataColumn2Increment int)update UserData2 set [LastModified]=getutcdate(), [DataColumn2]=[DataColumn2][email protected] where [UserId][email protected]
resource-list
keylock hobtid=72057594039173120 dbid=17 objectname=database_name.dbo.UserData1 indexname=1 id=lock20ec75b380 mode=X associatedObjectId=72057594039173120
owner-list
owner id=process20fd055498 mode=X
waiter-list
waiter id=process20fda2ccf8 mode=S requestType=wait
keylock hobtid=72057594039107584 dbid=17 objectname=database_name.dbo.UserData2 indexname=1 id=lock20ec07f600 mode=S associatedObjectId=72057594039107584
owner-list
owner id=process20fda2ccf8 mode=S
waiter-list
waiter id=process20fd055498 mode=X requestType=wait
जाहिर प्रक्रिया SELECT कथन को चलाने से पहले [UserData1] मेज पर [UserData2] एक ताला हासिल कर ली:
इस गतिरोध का पता लगाने से अंश है।
हां, मुझे डेडलॉक्स मिल रहा है। मैंने एक डेडलॉक ट्रेस के साथ सवाल अपडेट किया। ऐसा लगता है कि पहले लॉक को छोड़ने के बजाय [UserData1] पर अन्य लॉक प्राप्त करने का प्रयास करते समय SELECT क्वेरी को चलने वाली प्रक्रिया पहले लॉक ([UserData2]) पर रखती है। –