2013-07-12 14 views
8

मेरे पास दो बहुत ही सरल सारणी हैं, चलिए उन्हें [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] एक ताला हासिल कर ली:

इस गतिरोध का पता लगाने से अंश है।

उत्तर

0

पहली बात (मुझे लगता है) यह है कि पहली क्वेरी में आपका क्लॉज अनावश्यक है। आपके पास शामिल होने में एक ही चीज़ है और इसमें शामिल होने में बेहतर है क्योंकि आप एक पूर्ण बाहरी शामिल कर रहे हैं।

डेडलॉक्स से बचने के मामले में, संभवतः इसे पढ़ने के लॉक को छोड़ने के मामले में पहली क्वेरी को कैसे संभाला जाता है, इसके साथ यह करना होगा। यदि एप्लिकेशन केवल डेटा पढ़ रहा है और यह उपयोगकर्ता लेनदेन का हिस्सा नहीं है, तो एक बार पढ़ा जाने के बाद दूसरी क्वेरी पूरी हो जाएगी और आपको डेडलॉक नहीं मिलेगा।

क्या आपको अपने पर्यावरण में डेडलॉक मिल रहा है, या सिर्फ यह अनुमान लगा रहा है कि आपको डेडलॉक मिलेगा। यदि आप डेडलॉक ग्राफ पोस्ट कर रहे हैं तो हम देख सकते हैं कि वास्तविक लॉक क्या है।

+0

हां, मुझे डेडलॉक्स मिल रहा है। मैंने एक डेडलॉक ट्रेस के साथ सवाल अपडेट किया। ऐसा लगता है कि पहले लॉक को छोड़ने के बजाय [UserData1] पर अन्य लॉक प्राप्त करने का प्रयास करते समय SELECT क्वेरी को चलने वाली प्रक्रिया पहले लॉक ([UserData2]) पर रखती है। –

1

READ COMMITTED के साथ चयन को डेडलॉक में भाग नहीं लेना चाहिए क्योंकि इसे केवल एक समय में एक लॉक प्राप्त करना चाहिए। लॉक पंक्ति को पढ़ने के तुरंत बाद लॉक जारी किया जा सकता है।

मैं आपको सलाह देता हूं कि आप स्नैपशॉट अलगाव चालू करें। यह इस मुद्दे को हल करेगा।शामिल 3 ओवरहेड के साथ खुद को परिचित करें: पंक्ति का आकार बढ़ाया गया है, tempdb लिखता है और छोटे ओवरहेड पढ़ता है। ज्यादातर समय वे सार्थक नहीं हैं।

+0

सहमत हैं कि स्नैपशॉट अलगाव इस मुद्दे को हल करेगा, और शायद ओवरहेड नगण्य होगा। मैं सिर्फ उत्सुक हूं अगर इसे अन्य माध्यमों से हल किया जा सकता है। उदाहरण के लिए, क्या इसे व्यवस्थित किया जा सकता है ताकि टेबल में एक बार लॉक हो जाएं? डेडलॉक ट्रेस (प्रश्न शरीर में जोड़ा गया) से ऐसा लगता है कि एक तालिका ([UserData2]) पर लॉक जारी नहीं किया गया है जबकि SELECT अन्य तालिका को लॉक करने का प्रयास करता है। –

+0

एक्स-लॉक कभी रिलीज़ नहीं होते हैं ताकि रोलबैक काम करने की गारंटी हो। मैं और अधिक परेशान हूं क्यों चयन एक ही समय में एक से अधिक ताला लेगा? एसक्यूएल सर्वर आम तौर पर पंक्तियों को ताला लगाता है, टेबल नहीं। आपको इसे डीबग करना चाहिए। क्या चुनिंदा लेनदेन का कोई अन्य प्रश्न हिस्सा हैं? 'सेट ट्रांज़ेक्शन इशोलेशन लेवल कमेटेड' जोड़ें। आप अपडेट में तालिकाओं को 'टैबब्लैक' द्वारा ठीक कर सकते हैं लेकिन यह समवर्तीता के लिए भयानक है। शायद आपको अपनी चुनिंदा क्वेरी में उसी क्रम में एक्स-लॉक करने की भी आवश्यकता है। – usr

संबंधित मुद्दे