2010-04-29 26 views
7

मुझे SQL सर्वर 2005 पर एकाधिक deadlocks के साथ कोई समस्या है। यह एक INSERT और एक SELECT कथन के बीच है।INSERT और SELECT कथन के बीच SQL सर्वर डेडलॉक

दो टेबल हैं। तालिका 1 और तालिका 2। तालिका 2 में तालिका 1 का पीके (table1_id) विदेशी कुंजी के रूप में है।
table1_id पर इंडेक्स क्लस्टर किया गया है।

INSERT एक समय में तालिका 2 में एक पंक्ति डालता है।
एसईएलसीईटी 2 टेबल में शामिल हो जाता है। (यह एक लंबी क्वेरी है जो चलाने के लिए 12 सेकंड तक लग सकती है)

मेरी समझ (और प्रयोगों) के अनुसार आईएनएसईआरटी को रेफरेंसियल अखंडता की जांच करने के लिए तालिका 1 पर एक आईएस लॉक प्राप्त करना चाहिए (जो डेडलॉक नहीं बनना चाहिए)।

<deadlock-list> 
<deadlock victim="process968898"> 
    <process-list> 
    <process id="process8db1f8" taskpriority="0" logused="2424" waitresource="OBJECT: 5:789577851:0 " waittime="12390" ownerId="61831512" transactionname="user_transaction" lasttranstarted="2010-04-16T07:10:13.347" XDES="0x222a8250" lockMode="IX" schedulerid="1" kpid="3764" status="suspended" spid="52" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-04-16T07:10:13.350" lastbatchcompleted="2010-04-16T07:10:13.347" clientapp=".Net SqlClient Data Provider" hostname="VIDEV01-B-ME" hostpid="3040" loginname="DatabaseName" isolationlevel="read uncommitted (1)" xactid="61831512" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
    <executionStack> 
    <frame procname="DatabaseName.dbo.prcTable2_Insert" line="18" stmtstart="576" stmtend="1148" sqlhandle="0x0300050079e62d06e9307f000b9d00000100000000000000"> 
INSERT INTO dbo.Table2 
    (
     f1, 
     table1_id, 
     f2 
    ) 
    VALUES 
    (
     @p1, 
     @p_DocumentVersionID, 
     @p1 

    )  </frame> 
    </executionStack> 
    <inputbuf> 
Proc [Database Id = 5 Object Id = 103671417] </inputbuf> 
    </process> 
    <process id="process968898" taskpriority="0" logused="0" waitresource="PAGE: 5:1:46510" waittime="7625" ownerId="61831406" transactionname="INSERT" lasttranstarted="2010-04-16T07:10:12.717" XDES="0x418ec00" lockMode="S" schedulerid="2" kpid="1724" status="suspended" spid="53" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-04-16T07:10:12.713" lastbatchcompleted="2010-04-16T07:10:12.713" clientapp=".Net SqlClient Data Provider" hostname="VIDEV01-B-ME" hostpid="3040" loginname="DatabaseName" isolationlevel="read committed (2)" xactid="61831406" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
    <executionStack> 
    <frame procname="DatabaseName.dbo.prcGetList" line="64" stmtstart="3548" stmtend="11570" sqlhandle="0x03000500dbcec17e8d267f000b9d00000100000000000000"> 
     <!-- XXXXXXXXXXXXXX...SELECT STATEMENT WITH Multiple joins including both Table2 table 1 and .... XXXXXXXXXXXXXXX --> 
    </frame> 
    </executionStack> 
    <inputbuf> 
Proc [Database Id = 5 Object Id = 2126630619] </inputbuf> 
    </process> 
    </process-list> 
    <resource-list> 
    <pagelock fileid="1" pageid="46510" dbid="5" objectname="DatabaseName.dbo.table1" id="lock6236bc0" mode="IX" associatedObjectId="72057594042908672"> 
    <owner-list> 
    <owner id="process8db1f8" mode="IX"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="process968898" mode="S" requestType="wait"/> 
    </waiter-list> 
    </pagelock> 
    <objectlock lockPartition="0" objid="789577851" subresource="FULL" dbid="5" objectname="DatabaseName.dbo.Table2" id="lock970a240" mode="S" associatedObjectId="789577851"> 
    <owner-list> 
    <owner id="process968898" mode="S"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="process8db1f8" mode="IX" requestType="wait"/> 
    </waiter-list> 
    </objectlock> 
    </resource-list> 
</deadlock> 
</deadlock-list> 

किसी को भी क्यों सम्मिलित नौवीं पृष्ठ लॉक हो जाता है व्याख्या कर सकते हैं: लेकिन, इस मामले में यह एक नौवीं पेज का अधिग्रहण में

गतिरोध रिपोर्ट ताला?
क्या मैं डेडलॉक रिपोर्ट ठीक से नहीं पढ़ रहा हूं?
बीटीडब्ल्यू, मैं इस मुद्दे को पुन: उत्पन्न करने में कामयाब नहीं रहा हूं।

धन्यवाद!

संपादित करें: तालिकाएं सृजन:

CREATE TABLE [dbo].[Table2] (
    [Table2_id] [int] IDENTITY (1, 1) NOT NULL , 
    [f1] [int] NULL , 
    [Table1_id] [int] NOT NULL , 
    [f2] [int] NOT NULL , 
) 

ALTER TABLE [dbo].[Table2] ADD 
    CONSTRAINT [FK_Table2_Table1] FOREIGN KEY 
    (
     [Table1_id] 
    ) REFERENCES [dbo].[Table1] (
     [Table1_id] 
    ) 


CREATE TABLE [dbo].[Table1] (
    [Table1_id] [int] IDENTITY (1, 1) NOT NULL , 
) 

ALTER TABLE [dbo].[Table1] WITH NOCHECK ADD 
    CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED 
    (
     [Table1_id] 
    ) 
+0

क्या आप टेबल और विदेशी कुंजी के लिए डीडीएल स्टेटमेंट जोड़ सकते हैं? –

उत्तर

2

एक बाज़ी में, मैं कहता था कि DatabaseName.dbo.prcTable2_Insert एक सौदे के अंदर निष्पादित हो रहा है या स्पष्ट रूप से एक को खोलता है, और यह (या खुले के सिलसिले लेनदेन) पहले से ही तालिका 1 में पहले से ही एक सम्मिलित किया है।

+0

मुझे लगता है कि आपको मुझे सही रास्ते पर मिला है। मुझे सम्मिलित करने के लिए कॉल के बाद टैबलेट 1 के अपडेट के साथ एक लेनदेन मिला है। लॉकिंग ऑर्डर अभी भी मुझे समझ में नहीं आता है। इसकी आवश्यकता होने से पहले इसे एक आईएक्स लॉक क्यों मिलता है? डालने के बाद लॉक को बढ़ाना नहीं चाहिए? – dtroy

+0

बीटीडब्ल्यू, मैं अभी भी इसे खुद पुन: पेश नहीं कर सकता। मैंने उन दो इन्सेट्स/अपडेट्स के साथ एक लेनदेन बनाया है, एक लूप को भागने के साथ समानांतर में लूप में भाग लिया है। कोई विचार ? – dtroy

+0

@dtroy - मुझे डर है कि मेरे पास सुझाव देने के लिए बहुत कुछ नहीं है, इसे पुन: उत्पन्न करने की क्षमता अनुपस्थित है (और निश्चित रूप से, यदि आप इसे पुन: उत्पन्न करने में कामयाब होते हैं, तो मुझे संदेह है कि आपको वैसे भी अधिक सहायता की आवश्यकता होगी)। –

6

I का मतलब 'इरादा' ताला है, और वे हमेशा पदानुक्रमों से जुड़े होते हैं। चूंकि लॉक मैनेजर भौतिक संरचना को नहीं समझता है, इसलिए उनके लिए पदानुक्रमित ताले का सम्मान करना असंभव है, इसलिए पदानुक्रम इरादे ताले में फिर से बनाया गया है।

आपके मामले में INSERT के पास पृष्ठ पर एक इरादा लॉक है। इसका तात्पर्य यह है कि इसने पृष्ठ में एक पंक्ति पर एक एक्स लॉक भी प्राप्त किया है, जो सामान्य व्यवहार है। अब यह एक नया IX लॉक प्राप्त करने का प्रयास करता है, इसलिए इसे शायद किसी भिन्न पृष्ठ में एक पंक्ति डालने की आवश्यकता है। यह एकाधिक इंडेक्स वाले टेबल में डालने का सामान्य व्यवहार होगा: पहला IX इंडेक्स में से एक (संभव क्लस्टर्ड) पर है और दूसरा IX गैर क्लस्टर इंडेक्स पर है।

चयन जो आप कहते हैं कि 12 सेकेंड में रिटर्न होता है, इसलिए यह एक बड़ी क्वेरी सेट पर एक लंबी क्वेरी है, और योजना ने शायद एक उच्च लॉक ग्रैन्युलरिटी, पेज लॉक चुना है। SELECT में उस पृष्ठ पर एक एस लॉक है जो आईएनएसईआरटी आईएक्स लॉक चाहता है, और पेज पर एक और एस लॉक चाहता है कि आईएनएसईआरटी में आईएक्स लॉक है।

यह एक मामूली डेडलॉक है और इसे ठीक करना बहुत आसान होना चाहिए: सुनिश्चित करें कि आपके चयन को उन पृष्ठों को एस-लॉक की आवश्यकता नहीं है। यह यहां कोई INSERT गलती नहीं है। यह नहीं जानना कि SELECt क्या करता है मैं निश्चित रूप से यह नहीं कह सकता कि इष्टतम है या नहीं। मेरे अनुभव में, लगभग हमेशा इस तरह के एक चयन में सुधार के लिए बहुत, भरपूर और बहुत अधिक जगह है (स्वयं को चुनें या इसके नीचे स्कीमा)।

लेकिन स्वीकार करने कि चयन इष्टतम है, आपके लिए सबसे आसान मिल-बाहर के जेल कार्ड row versioning चालू करने के लिए है:

ALTER DATABASE <dbname> SET ALLOW_SNAPSHOT_ISOLATION ON; 
ALTER DATABASE <dbname> SET READ_COMMITTED_SNAPSHOT ON; 

अद्यतन:

दूसरी पढ़ने पर असल में

स्पष्ट है कि सम्मिलित करें अलग-अलग तालिकाओं पर ताले लगाए जाते हैं (जब तक आप एक्सएमएल को संशोधित नहीं करते हैं, जो यहां और वहां संपादित हाथ दिखता है), इसलिए को सम्मिलित करने के तरीके के बारे में आपकी व्याख्या गलत होनी चाहिए। आईएनएसईआरटी कम से कम दो लिखने की तुलना में एक लेनदेन का हिस्सा है, तालिका 1 पर एक और तालिका 2 पर एक। लेकिन यह समस्या और न ही समाधान को बदलता है। यह सच है कि लेनदेन में अलग-अलग लेन-देन में दो लिखने का एवेन्यू है, लेकिन यह स्पष्ट रूप से सबसे खराब एवेन्यू है।

+0

केवल एक ही लेखन होना चाहिए। मैंने चीजों को सरल बनाने और कुछ संवेदनशील नामों को हटाने के लिए xml को संशोधित किया है। – dtroy

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