नॉन-क्लस्टर्ड इंडेक्स के साथ अलग-अलग पंक्तियों को अपडेट करने पर गतिरोध


13

जब मैं आईडी फ़ील्ड पर संकुल और गैर-क्लस्टर किए गए अनुक्रमणिका का उपयोग करता हूं, तो मैंने देखा कि जब मैं लॉक व्यवहार को अलग करता हूं, तो मैं एक डेडलॉकिंग समस्या को हल कर रहा हूं। अगर गति सूचकांक या प्राथमिक कुंजी को आईडी फ़ील्ड पर लागू किया जाता है, तो गतिरोध समस्या हल हो गई लगती है।

मेरे पास अलग-अलग पंक्तियों में एक या एक से अधिक अपडेट करने वाले लेनदेन हैं, जैसे लेनदेन A केवल ID = a के साथ पंक्ति को अपडेट करेगा, tx B केवल ID = b आदि के साथ पंक्ति को स्पर्श करेगा।

और मुझे समझ में आया है कि सूचकांक के बिना, अपडेट सभी पंक्तियों के लिए अपडेट लॉक का अधिग्रहण करेगा और आवश्यक होने पर अनन्य लॉक को गुप्त करेगा, जो अंततः गतिरोध की ओर ले जाएगा। लेकिन मैं यह पता लगाने में विफल हूं कि गैर-क्लस्टर किए गए सूचकांक के साथ क्यों, गतिरोध अभी भी है (हालांकि हिट दर को गिरा दिया जा रहा है)

विवरण सारणी:

CREATE TABLE [dbo].[user](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [userName] [nvarchar](255) NULL,
    [name] [nvarchar](255) NULL,
    [phone] [nvarchar](255) NULL,
    [password] [nvarchar](255) NULL,
    [ip] [nvarchar](30) NULL,
    [email] [nvarchar](255) NULL,
    [pubDate] [datetime] NULL,
    [todoOrder] [text] NULL
)

डेडलॉक ट्रेस

deadlock-list
deadlock victim=process4152ca8
process-list
process id=process4152ca8 taskpriority=0 logused=0 waitresource=RID: 5:1:388:29 waittime=3308 ownerId=252354 transactionname=user_transaction lasttranstarted=2014-04-11T00:15:30.947 XDES=0xb0bf180 lockMode=U schedulerid=3 kpid=11392 status=suspended spid=57 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2014-04-11T00:15:30.953 lastbatchcompleted=2014-04-11T00:15:30.950 lastattention=1900-01-01T00:00:00.950 clientapp=.Net SqlClient Data Provider hostname=BOOD-PC hostpid=9272 loginname=getodo_sql isolationlevel=read committed (2) xactid=252354 currentdb=5 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
executionStack
frame procname=adhoc line=1 stmtstart=62 sqlhandle=0x0200000062f45209ccf17a0e76c2389eb409d7d970b0f89e00000000000000000000000000000000
update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@owner
frame procname=unknown line=1 sqlhandle=0x00000000000000000000000000000000000000000000000000000000000000000000000000000000
unknown
inputbuf
(@para0 nvarchar(2)<c/>@owner int)update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@owner
process id=process4153468 taskpriority=0 logused=4652 waitresource=KEY: 5:72057594042187776 (3fc56173665b) waittime=3303 ownerId=252344 transactionname=user_transaction lasttranstarted=2014-04-11T00:15:30.920 XDES=0x4184b78 lockMode=U schedulerid=3 kpid=7272 status=suspended spid=58 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2014-04-11T00:15:30.960 lastbatchcompleted=2014-04-11T00:15:30.960 lastattention=1900-01-01T00:00:00.960 clientapp=.Net SqlClient Data Provider hostname=BOOD-PC hostpid=9272 loginname=getodo_sql isolationlevel=read committed (2) xactid=252344 currentdb=5 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
executionStack
frame procname=adhoc line=1 stmtstart=60 sqlhandle=0x02000000d4616f250747930a4cd34716b610a8113cb92fbc00000000000000000000000000000000
update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@uid
frame procname=unknown line=1 sqlhandle=0x00000000000000000000000000000000000000000000000000000000000000000000000000000000
unknown
inputbuf
(@para0 nvarchar(61)<c/>@uid int)update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@uid
resource-list
ridlock fileid=1 pageid=388 dbid=5 objectname=SQL2012_707688_webows.dbo.user id=lock3f7af780 mode=X associatedObjectId=72057594042122240
owner-list
owner id=process4153468 mode=X
waiter-list
waiter id=process4152ca8 mode=U requestType=wait
keylock hobtid=72057594042187776 dbid=5 objectname=SQL2012_707688_webows.dbo.user indexname=10 id=lock3f7ad700 mode=U associatedObjectId=72057594042187776
owner-list
owner id=process4152ca8 mode=U
waiter-list
waiter id=process4153468 mode=U requestType=wait

इसके अलावा एक दिलचस्प और संभव संबंधित खोज यह है कि गुच्छेदार और गैर-संकुल सूचकांक में अलग-अलग लॉक व्यवहार होते हैं

क्लस्टर किए गए सूचकांक का उपयोग करते समय, कुंजी पर एक विशेष लॉक होता है और साथ ही अपडेट करते समय RID पर एक विशेष लॉक होता है, जो अपेक्षित है; जबकि दो अलग-अलग RID पर दो विशेष लॉक हैं यदि गैर-संकुल सूचकांक का उपयोग किया जाता है, जो मुझे भ्रमित करता है।

मददगार होगा अगर कोई समझा सकता है कि इस पर भी क्यों।

परीक्षण एसक्यूएल:

use SQL2012_707688_webows;
begin transaction;
update [user] with (rowlock) set todoOrder='{1}' where id = 63501
exec sp_lock;
commit;

आईडी के साथ संकुल सूचकांक के रूप में:

spid    dbid    ObjId   IndId   Type    Resource    Mode    Status
53  5   917578307   1   KEY (b1a92fe5eed4)                      X   GRANT
53  5   917578307   1   PAG 1:879                               IX  GRANT
53  5   917578307   1   PAG 1:1928                              IX  GRANT
53  5   917578307   1   RID 1:879:7                             X   GRANT

गैर-संकुल सूचकांक के रूप में आईडी के साथ

spid    dbid    ObjId   IndId   Type    Resource    Mode    Status
53  5   917578307   0   PAG 1:879                               IX  GRANT
53  5   917578307   0   PAG 1:1928                              IX  GRANT
53  5   917578307   0   RID 1:879:7                             X   GRANT
53  5   917578307   0   RID 1:1928:18                           X   GRANT

EDIT1: किसी इंडेक्स के बिना डेडलॉक का विवरण
कहो कि मेरे पास दो tx A और B हैं, प्रत्येक में दो अपडेट स्टेटमेंट्स, अलग-अलग पंक्ति ऑफ कोर्स
ax A

update [user] with (rowlock) set todoOrder='{1}' where id = 63501
update [user] with (rowlock) set todoOrder='{2}' where id = 63501

टीएक्स बी

update [user] with (rowlock) set todoOrder='{3}' where id = 63502
update [user] with (rowlock) set todoOrder='{4}' where id = 63502

{1} और {4} के बाद से गतिरोध का मौका होगा

{१} पर, U लॉक को ६३५०५ पंक्ति के लिए अनुरोध किया गया है क्योंकि इसे टेबल स्कैन करने की आवश्यकता है, और X लॉक को पंक्ति ६३५०१ पर रखा जा सकता है क्योंकि यह स्थिति से मेल खाता है

{4} पर, यू लॉक को पंक्ति 63501 के लिए अनुरोध किया गया है, और एक्स लॉक पहले से ही 63502 के लिए है

इसलिए हमारे पास txA की 63501 और वेटिंग 63502 है, जबकि txB के पास 63502 वेटिंग 63501 है, जो एक गतिरोध है

EDIT2: मेरे परीक्षण मामले की एक बग को बदल देता है, यहां एक अंतर स्थिति बनती है। क्षमा करें भ्रम के लिए लेकिन बग एक अंतर स्थिति बनाता है, और अंततः गतिरोध का कारण लगता है।

चूंकि पॉल के विश्लेषण ने वास्तव में इस मामले में मेरी मदद की इसलिए मैं इसे एक उत्तर के रूप में स्वीकार करूंगा।

मेरे परीक्षण मामले की बग के कारण, दो लेनदेन txA और txB एक ही पंक्ति को अपडेट कर सकते हैं, नीचे:

tx ए

update [user] with (rowlock) set todoOrder='{1}' where id = 63501
update [user] with (rowlock) set todoOrder='{2}' where id = 63501

टीएक्स बी

update [user] with (rowlock) set todoOrder='{3}' where id = 63501

{2} और {3} में गतिरोध का मौका होगा जब:

txA RID पर X लॉक रखते समय कुंजी पर U लॉक का अनुरोध करता है ({1} के अद्यतन के कारण) txB अनुरोधों पर U लॉक को आर लॉक करता है जबकि कुंजी पर U लॉक रखता है


1
मैं यह नहीं समझ सकता कि लेन-देन को एक ही पंक्ति को दो बार अपडेट करने की आवश्यकता क्यों है।
ypercube y

@ypercube अच्छा बिंदु, यह कुछ ऐसा है जिसे मुझे सुधारना चाहिए। लेकिन इस मामले में मैं सिर्फ लॉक व्यवहार की बेहतर समझ रखना चाहता हूं
Bood

@ypercube अधिक विचारों के बाद मुझे लगता है कि यह संभव है कि जटिल तर्क के साथ एक आवेदन को एक ही पंक्ति को दो बार एक ही tx में अपडेट करने की आवश्यकता हो, उदाहरण के लिए अलग कॉलम हो सकते हैं
Bood

जवाबों:


16

... क्यों क्लस्टर सूचकांक के साथ, गतिरोध अभी भी है (हालांकि हिट दर को गिरा दिया जा रहा है)

यह प्रश्न ठीक से स्पष्ट नहीं है (उदाहरण के लिए कि idप्रत्येक लेनदेन में कितने अपडेट और कौन से मान हैं) लेकिन एक स्पष्ट डेडलॉक परिदृश्य एक एकल लेनदेन के भीतर कई एकल-पंक्ति अपडेट के साथ उत्पन्न होता है, जहां [id]मानों का ओवरलैप होता है, और आईडी होते हैं एक अलग [id]क्रम में अद्यतन :

[T1]: Update id 2; Update id 1;
[T2]: Update id 1; Update id 2;

गतिरोध अनुक्रम: T1 (u2), T2 (u1), T1 (u1) प्रतीक्षा , T2 (u2) प्रतीक्षा करें

प्रत्येक लेन-देन के भीतर आईडी क्रम में कड़ाई से अपडेट करने (समान पथ पर समान क्रम में ताले प्राप्त करने) से इस गतिरोध अनुक्रम से बचा जा सकता है।

क्लस्टर किए गए सूचकांक का उपयोग करते समय, कुंजी पर एक विशेष लॉक होता है और साथ ही अपडेट करते समय RID पर एक विशेष लॉक होता है, जो अपेक्षित है; जबकि दो अलग-अलग RID पर दो विशेष लॉक हैं यदि गैर-संकुल सूचकांक का उपयोग किया जाता है, जो मुझे भ्रमित करता है।

इन पर अनूठे क्लस्टर किए गए इंडेक्स के साथ id, इन-रो डेटा में राइट्स को सुरक्षित रखने के लिए क्लस्टरिंग कुंजी पर एक विशेष लॉक लिया जाता है। RIDएलओबी textकॉलम को लिखने के लिए एक विशेष अनन्य लॉक की आवश्यकता होती है , जो डिफ़ॉल्ट रूप से एक अलग डेटा पेज पर संग्रहीत होता है।

जब टेबल केवल एक गैर-अनुक्रमित सूचकांक के साथ एक ढेर idहोता है, तो दो चीजें होती हैं। पहला, एक RIDएक्सक्लूसिव लॉक हीप इन-रो डेटा से संबंधित है, और दूसरा पहले की तरह LOB डेटा पर लॉक है। दूसरा प्रभाव यह है कि एक अधिक जटिल निष्पादन योजना की आवश्यकता है।

क्लस्टर किए गए अनुक्रमणिका और एक साधारण एकल-मूल्य समानता की भविष्यवाणी को अपडेट करने के साथ, क्वेरी प्रोसेसर एक अनुकूलन लागू कर सकता है जो एकल संचालक का उपयोग करके एकल संचालक में अद्यतन (पढ़ना और लिखना) करता है:

सिंगल-ऑपरेटर अपडेट

पंक्ति एक एकल ऑपरेशन में स्थित है और केवल अनन्य ताले की आवश्यकता है (कोई अद्यतन ताले की आवश्यकता नहीं है)। अपनी नमूना तालिका का उपयोग करके एक उदाहरण लॉकिंग अनुक्रम:

acquiring IX lock on OBJECT: 6:992930809:0 -- TABLE
acquiring IX lock on PAGE: 6:1:59104 -- INROW
acquiring X lock on KEY: 6:72057594233618432 (61a06abd401c) -- INROW
acquiring IX lock on PAGE: 6:1:59091 -- LOB
acquiring X lock on RID: 6:1:59091:1 -- LOB

releasing lock reference on PAGE: 6:1:59091 -- LOB
releasing lock reference on RID: 6:1:59091:1 -- LOB
releasing lock reference on KEY: 6:72057594233618432 (61a06abd401c) -- INROW
releasing lock reference on PAGE: 6:1:59104 -- INROW

केवल एक गैर-अनुक्रमित सूचकांक के साथ, एक ही अनुकूलन लागू नहीं किया जा सकता है क्योंकि हमें एक बी-ट्री संरचना से पढ़ना और दूसरा लिखना होगा। बहु-पथ योजना के अलग-अलग चरण हैं और पढ़ें:

मल्टी-इटरेटर अपडेट

यह पढ़ते समय अद्यतन ताले को प्राप्त कर लेता है, यदि पंक्ति योग्य हो तो अनन्य ताले में परिवर्तित। उदाहरण दिए गए स्कीमा के साथ लॉक अनुक्रम:

acquiring IX lock on OBJECT: 6:992930809:0 -- TABLE
acquiring IU lock on PAGE: 6:1:59105 -- NC INDEX
acquiring U lock on KEY: 6:72057594233749504 (61a06abd401c) -- NC INDEX
acquiring IU lock on PAGE: 6:1:59104 -- HEAP
acquiring U lock on RID: 6:1:59104:1 -- HEAP
acquiring IX lock on PAGE: 6:1:59104 -- HEAP convert to X
acquiring X lock on RID: 6:1:59104:1 -- HEAP convert to X
acquiring IU lock on PAGE: 6:1:59091 -- LOB
acquiring U lock on RID: 6:1:59091:1 -- LOB

releasing lock reference on PAGE: 6:1:59091 
releasing lock reference on RID: 6:1:59091:1
releasing lock reference on RID: 6:1:59104:1
releasing lock reference on PAGE: 6:1:59104 
releasing lock on KEY: 6:72057594233749504 (61a06abd401c)
releasing lock on PAGE: 6:1:59105 

ध्यान दें कि LOB डेटा टेबल अपडेट पुनरावृत्ति पर पढ़ा और लिखा गया है। अधिक जटिल योजना और कई पढ़ने और लिखने के रास्ते एक गतिरोध की संभावना को बढ़ाते हैं।

अंत में, मैं मदद नहीं कर सकता, लेकिन तालिका परिभाषा में उपयोग किए गए डेटा प्रकारों को नोटिस कर सकता हूं। आपको textनए काम के लिए पदावनत डेटा प्रकार का उपयोग नहीं करना चाहिए ; विकल्प, यदि आपको वास्तव में इस कॉलम में 2GB तक डेटा स्टोर करने की क्षमता की आवश्यकता है, तो है varchar(max)। के बीच एक महत्वपूर्ण अंतर textऔर varchar(max)है कि textडेटा बंद पंक्ति डिफ़ॉल्ट रूप से संग्रहीत किया जाता है, जबकि varchar(max)इन-पंक्ति डिफ़ॉल्ट रूप से स्टोर।

यूनिकोड प्रकारों का उपयोग केवल तभी करें जब आपको उस लचीलेपन की आवश्यकता हो (जैसे यह देखना कठिन है कि आईपी पते को यूनिकोड की आवश्यकता क्यों होगी)। इसके अलावा, अपनी विशेषताओं के लिए उचित लंबाई सीमा चुनें - 255 हर जगह सही होने की संभावना नहीं लगती है।

अतिरिक्त पढ़ना:
डेडलॉक और लाइवलॉक सामान्य पैटर्न
बार्ट डंकन का गतिरोध समस्या निवारण श्रृंखला

ट्रेसिंग लॉक विभिन्न तरीकों से किया जा सकता है। उन्नत सेवाओं के साथ SQL सर्वर एक्सप्रेस ( केवल 2014 और 2012 SP1 आगे ) में Profiler टूल है, जो लॉक अधिग्रहण और रिलीज़ के विवरण को देखने के लिए एक समर्थित तरीका है।


बहुत बढ़िया जवाब। आप उन लॉग / ट्रेस का आउटपुट कैसे दे रहे हैं जिनमें "प्राप्त करना ... लॉक" और "लॉक रेफरेंस जारी करना" संदेश हैं?
संजीव जीवन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.