क्या मैं आदेश में SQL सर्वर पहचान मान पढ़ने पर भरोसा कर सकता हूं?


24

टीएल; डीआर: नीचे दिए गए प्रश्न नीचे उबलते हैं: जब एक पंक्ति सम्मिलित करते हैं, तो एक नए मूल्य की पीढ़ीIdentity और क्लस्टर इंडेक्स में संबंधित पंक्ति कुंजी के लॉक होने के बीच अवसर की एक खिड़की होती है, जहां एक बाहरी पर्यवेक्षक एक नया देख सकता है। Identityसमवर्ती लेनदेन द्वारा डाला गया मूल्य? (SQL सर्वर में।)

विस्तृत संस्करण

मेरे पास एक Identityकॉलम के साथ एक SQL सर्वर टेबल है CheckpointSequence, जो टेबल के क्लस्टर इंडेक्स की कुंजी है (जिसमें कई अतिरिक्त गैर-अनुक्रमित इंडेक्स भी हैं)। पंक्तियों को कई समवर्ती प्रक्रियाओं और थ्रेड्स (अलगाव स्तर पर , और बिना ) द्वारा तालिका में डाला जाता है । उसी समय, उस कॉलम द्वारा आदेशित क्लस्टर इंडेक्स से समय-समय पर पंक्तियों को पढ़ने की प्रक्रिया होती है, (अलगाव स्तर पर , विकल्प बंद होने के साथ )।READ COMMITTEDIDENTITY_INSERTCheckpointSequenceREAD COMMITTEDREAD COMMITTED SNAPSHOT

मैं वर्तमान में इस तथ्य पर भरोसा करता हूं कि पढ़ने की प्रक्रिया कभी भी एक चेकपॉइंट को "छोड़" नहीं सकती है। मेरा सवाल है: क्या मैं इस संपत्ति पर भरोसा कर सकता हूं? और अगर नहीं, तो मैं इसे सच करने के लिए क्या कर सकता था?

उदाहरण: जब पहचान मान 1, 2, 3, 4, और 5 वाली पंक्तियों को डाला जाता है, तो पाठक को मान 5 के साथ देखने से पहले पंक्ति 5 को नहीं देखना चाहिए । परीक्षण से पता चलता है कि क्वेरी, जिसमें एक ORDER BY CheckpointSequenceखंड है ( और एक WHERE CheckpointSequence > -1खंड), जब भी पंक्ति 4 को पढ़ना है, तो विश्वसनीय रूप से ब्लॉक करता है, लेकिन अभी तक प्रतिबद्ध नहीं है, भले ही पंक्ति 5 पहले से ही प्रतिबद्ध हो।

मेरा मानना ​​है कि कम से कम सिद्धांत रूप में, यहां एक दौड़ की स्थिति हो सकती है जो इस धारणा को तोड़ सकती है। दुर्भाग्य से, दस्तावेज़ीकरण कई समवर्ती लेनदेन के संदर्भ में Identityकैसे Identityकाम करता है, इसके बारे में बहुत कुछ नहीं कहता है , यह केवल कहता है "प्रत्येक नया मूल्य वर्तमान बीज और वेतन वृद्धि के आधार पर उत्पन्न होता है।" और "किसी विशेष लेनदेन के लिए प्रत्येक नया मूल्य तालिका के अन्य समवर्ती लेनदेन से अलग है।" ( MSDN )

मेरा तर्क है, यह किसी तरह काम करना चाहिए:

  1. एक लेन-देन शुरू किया जाता है (या तो स्पष्ट रूप से या अंतर्निहित रूप से)।
  2. एक पहचान मूल्य (X) उत्पन्न होता है।
  3. पहचान मूल्य के आधार पर क्लस्टर इंडेक्स पर संबंधित पंक्ति लॉक लिया जाता है (जब तक कि लॉक एस्केलेशन अंदर न हो जाए, जिस स्थिति में पूरी टेबल लॉक हो जाती है)।
  4. पंक्ति डाली गई है।
  5. लेनदेन प्रतिबद्ध है (संभवतः बाद में काफी समय), इसलिए ताला फिर से हटा दिया जाता है।

मुझे लगता है कि चरण 2 और 3 के बीच, एक बहुत छोटी खिड़की है जहां

  • एक समवर्ती सत्र अगले पहचान मूल्य (X + 1) उत्पन्न कर सकता है और सभी शेष चरणों को निष्पादित कर सकता है,
  • इस प्रकार एक पाठक को उस समय के मूल्य X + 1 को पढ़ने की अनुमति देता है, जिससे X का मान गायब हो जाता है।

बेशक, इस की संभावना बेहद कम लगती है; लेकिन फिर भी - ऐसा हो सकता है। या कर सकता था?

(यदि आप संदर्भ में रुचि रखते हैं: यह NEventStore के एसक्यूएल पर्सिस्टेंस इंजन का कार्यान्वयन है। NEventStore एपेंड-ओनली इवेंट स्टोर पर लागू होता है, जहां हर ईवेंट को एक नया, आरोही चेकपॉइंट अनुक्रम संख्या मिलती है। ग्राहक चेकपॉइंट द्वारा ऑर्डर किए गए इवेंट स्टोर से घटनाओं को पढ़ते हैं। सभी प्रकार की संगणनाएँ करने के लिए। एक बार जब चेकपॉइंट X के साथ कोई घटना संसाधित हो जाती है, तो ग्राहक केवल "नई" घटनाओं पर विचार करते हैं, यानी, चेकपॉइंट X + 1 और इसके बाद की घटनाओं के साथ। इसलिए, यह महत्वपूर्ण है कि घटनाओं को कभी भी छोड़ा नहीं जा सकता है, जैसा कि उन्हें फिर से कभी नहीं माना जाएगा। मैं वर्तमान में यह निर्धारित करने की कोशिश कर रहा हूं कि Identity-बेड चेकपॉइंट कार्यान्वयन इस आवश्यकता को पूरा करता है। ये उपयोग किए गए सटीक एसक्यूएल बयान हैं : स्कीमा , राइटर की क्वेरी ,रीडर की क्वेरी ।)

यदि मैं सही हूं और ऊपर वर्णित स्थिति उत्पन्न हो सकती है, तो मैं उनके साथ निपटने के केवल दो विकल्प देख सकता हूं, दोनों ही असंतोषजनक हैं:

  • X को देखने से पहले चेकपॉइंट अनुक्रम मान X + 1 को देखते समय, X + 1 को खारिज कर दें और बाद में पुनः प्रयास करें। हालाँकि, क्योंकि Identityनिश्चित रूप से अंतराल उत्पन्न कर सकते हैं (उदाहरण के लिए, जब लेन-देन वापस ले लिया जाता है), एक्स कभी नहीं आ सकता है।
  • तो, एक ही दृष्टिकोण, लेकिन n मिलीसेकंड के बाद अंतर को स्वीकार करें। हालाँकि, मुझे n का क्या मान लेना चाहिए?

कोई बेहतर विचार?


क्या आपने पहचान के बजाय अनुक्रम का उपयोग करने की कोशिश की है? पहचान के साथ, मुझे नहीं लगता कि आप मज़बूती से अनुमान लगा सकते हैं कि कौन सा इन्सर्ट एक विशेष पहचान मूल्य प्राप्त करेगा लेकिन यह एक अनुक्रम का उपयोग करके समस्या नहीं होनी चाहिए। बेशक, यह बदलता है कि आप चीजों को अब कैसे करते हैं।
एंटोनी हर्नांडेज़

@SoleDBAGuy क्या एक सीक्वेंस रेस की स्थिति नहीं बना देगा जो मैंने ऊपर वर्णित की है और भी अधिक होने की संभावना है? मैं एक नया अनुक्रम मूल्य एक्स (ऊपर चरण 2 की जगह) का उत्पादन करता हूं, फिर एक पंक्ति (चरण 3 और 4) डालें। 2 और 3 के बीच, वहाँ एक संभावना है कि किसी और अगले अनुक्रम मूल्य एक्स + 1 का उत्पादन हो सकता है यह करता है, और एक पाठक पढ़ता है कि मूल्य एक्स + 1 इससे पहले कि मैं भी अनुक्रम मूल्य X के साथ मेरी पंक्ति सम्मिलित करने के लिए मिलता है
फैबियन Schmied

जवाबों:


26

एक पंक्ति सम्मिलित करते समय, क्या नई पहचान मूल्य की पीढ़ी और संकुल सूचकांक में संबंधित पंक्ति कुंजी की लॉकिंग के बीच अवसर की एक खिड़की है, जहां एक बाहरी पर्यवेक्षक एक समवर्ती लेनदेन द्वारा डाली गई एक नई पहचान मूल्य देख सकता है?

हाँ।

पहचान मूल्यों के आवंटन युक्त उपयोगकर्ता लेन-देन से स्वतंत्र है । यह एक कारण है कि पहचान मूल्यों का उपभोग किया जाता है, भले ही लेनदेन वापस आ जाए। वेतनवृद्धि का संचालन भ्रष्टाचार को रोकने के लिए एक कुंडी द्वारा किया जाता है, लेकिन यह सुरक्षा की सीमा है।

आपके कार्यान्वयन की विशिष्ट परिस्थितियों में, पहचान आबंटन (कॉल CMEDSeqGen::GenerateNewValue) को सम्मिलित करने के लिए उपयोगकर्ता लेनदेन से पहले भी सक्रिय किया जाता है (और इससे पहले कि कोई भी लॉक लिया जाए)।

पहचान के मूल्य में वृद्धि और आवंटन के बाद मुझे एक थ्रेड को फ्रीज करने की अनुमति देने के लिए संलग्न डिबगर के साथ समवर्ती दो आवेषण चलाकर, मैं एक परिदृश्य को पुन: पेश करने में सक्षम था जहां:

  1. सत्र 1 एक पहचान मूल्य प्राप्त करता है (3)
  2. सत्र 2 एक पहचान मूल्य प्राप्त करता है (4)
  3. सत्र 2 अपनी प्रविष्टि करता है और करता है (ताकि पंक्ति 4 पूरी तरह से दिखाई दे)
  4. सत्र 1 अपनी प्रविष्टि करता है और करता है (पंक्ति 3)

चरण 3 के बाद, लॉकिंग रीड प्रतिबद्ध के तहत row_number का उपयोग करके एक क्वेरी निम्नलिखित को लौटा दी गई:

स्क्रीनशॉट

आपके कार्यान्वयन में, यह चेकपॉइंट ID 3 में गलत तरीके से छोड़ दिया जाएगा।

मिसोपोर्ट्यूनिटी की खिड़की अपेक्षाकृत छोटी है, लेकिन यह मौजूद है। डिबगर संलग्न होने की तुलना में अधिक यथार्थवादी परिदृश्य देने के लिए: एक निष्पादित क्वेरी थ्रेड ऊपर चरण 1 के बाद शेड्यूलर प्राप्त कर सकता है। मूल थ्रेड को इसकी प्रविष्टि करने के लिए फिर से शुरू करने से पहले एक दूसरे थ्रेड को एक पहचान मान आवंटित करने और सम्मिलित करने की अनुमति देता है।

स्पष्टता के लिए, कोई भी लॉकेट या अन्य सिंक्रोनाइज़ेशन ऑब्जेक्ट नहीं हैं जो पहचान मूल्य को आवंटित करने और उपयोग करने से पहले उसकी सुरक्षा करते हैं। उदाहरण के लिए, चरण 1 से ऊपर के बाद, एक समवर्ती लेन-देन IDENT_CURRENTतालिका में पंक्ति के मौजूद होने से पहले की तरह (यहां तक ​​कि अप्रकाशित) भी नए पहचान मूल्य का उपयोग कर सकता है।

मूल रूप से, दस्तावेज की तुलना में पहचान मूल्यों के आसपास कोई और गारंटी नहीं है :

  • प्रत्येक नया मान वर्तमान बीज और वृद्धि के आधार पर उत्पन्न होता है।
  • किसी विशेष लेनदेन के लिए प्रत्येक नया मूल्य तालिका के अन्य समवर्ती लेनदेन से अलग है।

वाकई ऐसा है।

यदि सख्त लेनदेन एफआईएफओ प्रसंस्करण की आवश्यकता है, तो आपके पास मैन्युअल रूप से अनुक्रमित करने के अलावा कोई विकल्प नहीं है। यदि आवेदन में कम आवश्यकताएं हैं, तो आपके पास अधिक विकल्प हैं। उस संबंध में प्रश्न 100% स्पष्ट नहीं है। फिर भी, आप कुछ उपयोगी जानकारी रेमुस रुसानू के लेख टेबल्स क्वे के रूप में उपयोग कर सकते हैं ।


7

जैसा कि पॉल व्हाइट ने बिल्कुल सही उत्तर दिया था कि अस्थायी रूप से "स्किप" पहचान पंक्तियों के लिए एक संभावना है। इस कोड को अपने खुद के लिए पुन: पेश करने के लिए यहां सिर्फ एक छोटा सा कोड है।

एक डेटाबेस और एक परीक्षण योग्य बनाएं:

create database IdentityTest
go
use IdentityTest
go
create table dbo.IdentityTest (ID int identity, c1 char(10))
create clustered index CI_dbo_IdentityTest_ID on dbo.IdentityTest(ID)

C # कंसोल प्रोग्राम में इस तालिका पर समवर्ती आवेषण और चयन करें:

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading;

namespace IdentityTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var insertThreads = new List<Thread>();
            var selectThreads = new List<Thread>();

            //start threads for infinite inserts
            for (var i = 0; i < 100; i++)
            {
                insertThreads.Add(new Thread(InfiniteInsert));
                insertThreads[i].Start();
            }

            //start threads for infinite selects
            for (var i = 0; i < 10; i++)
            {
                selectThreads.Add(new Thread(InfiniteSelectAndCheck));
                selectThreads[i].Start();
            }
        }

        private static void InfiniteSelectAndCheck()
        {
            //infinite loop
            while (true)
            {
                //read top 2 IDs
                var cmd = new SqlCommand("select top(2) ID from dbo.IdentityTest order by ID desc")
                {
                    Connection = new SqlConnection("Server=localhost;Database=IdentityTest;Integrated Security=SSPI;Application Name=IdentityTest")
                };

                try
                {
                    cmd.Connection.Open();
                    var dr = cmd.ExecuteReader();

                    //read first row
                    dr.Read();
                    var row1 = int.Parse(dr["ID"].ToString());

                    //read second row
                    dr.Read();
                    var row2 = int.Parse(dr["ID"].ToString());

                    //write line if row1 and row are not consecutive
                    if (row1 - 1 != row2)
                    {
                        Console.WriteLine("row1=" + row1 + ", row2=" + row2);
                    }
                }
                finally
                {
                    cmd.Connection.Close();
                }
            }
        }

        private static void InfiniteInsert()
        {
            //infinite loop
            while (true)
            {
                var cmd = new SqlCommand("insert into dbo.IdentityTest (c1) values('a')")
                {
                    Connection = new SqlConnection("Server=localhost;Database=IdentityTest;Integrated Security=SSPI;Application Name=IdentityTest")
                };

                try
                {
                    cmd.Connection.Open();
                    cmd.ExecuteNonQuery();
                }
                finally
                {
                    cmd.Connection.Close();
                }
            }
        }
    }
}

यह कंसोल हर मामले के लिए एक लाइन प्रिंट करता है जब रीडिंग थ्रेड्स में से एक प्रविष्टि "मिस" हो जाती है।


1
अच्छा कोड है, लेकिन आप केवल लगातार आईडी ( "// पंक्ति लिखें यदि पंक्ति 1 और पंक्ति लगातार नहीं हैं" )। उत्पन्न अंतराल हो सकते हैं कि आपका कोड प्रिंट होगा। इसका मतलब यह नहीं है कि ये अंतराल बाद में भरे जाएंगे।
ypercube y

1
क्योंकि कोड एक परिदृश्य को ट्रिगर नहीं करता है, जहां IDENTITYअंतराल पैदा करेगा (जैसे कि एक लेनदेन को वापस करना), मुद्रित लाइनें वास्तव में "स्किप्ड" मान दिखाती हैं (या कम से कम वे तब करते हैं जब मैं भाग गया और मेरी मशीन पर इसकी जांच की गई)। बहुत अच्छा रेप्रो नमूना!
फेबियन श्मिड

5

पहचानों की निरंतरता की उम्मीद नहीं करना सबसे अच्छा है क्योंकि कई परिदृश्य हैं जो अंतराल छोड़ सकते हैं। एक अमूर्त संख्या की तरह पहचान पर विचार करना और किसी भी व्यवसाय के अर्थ को संलग्न न करना बेहतर है।

मूल रूप से, अंतराल तब हो सकता है जब आप INSERT ऑपरेशन (या स्पष्ट रूप से पंक्तियों को हटा दें) को रोल करते हैं, और डुप्लिकेट हो सकता है यदि आप तालिका गुण IDENTITY_INSERT को चालू करते हैं।

अंतराल तब हो सकती है जब:

  1. रिकॉर्ड हटा दिए जाते हैं।
  2. नया रिकॉर्ड सम्मिलित करने का प्रयास करते समय एक त्रुटि आई (वापस लुढ़का)
  3. एक अपडेट / स्पष्ट मूल्य (पहचान_ विकल्प) के साथ डालें।
  4. वृद्धिशील मान 1 से अधिक है।
  5. एक लेन-देन वापस आता है।

एक स्तंभ पर पहचान संपत्ति की कभी गारंटी नहीं दी गई है:

• विशिष्टता

• एक लेन-देन के भीतर लगातार मूल्यों। यदि मान लगातार होना चाहिए, तो लेन-देन को टेबल पर एक विशेष लॉक का उपयोग करना चाहिए या सर्जिकल आकार के अलगाव स्तर का उपयोग करना चाहिए।

सर्वर रिस्टार्ट के बाद लगातार मान।

• मूल्यों का पुन: उपयोग।

यदि आप इसके कारण पहचान मानों का उपयोग नहीं कर सकते हैं, तो एक वर्तमान मान रखने वाली एक अलग तालिका बनाएं और अपने आवेदन के साथ तालिका और संख्या असाइनमेंट तक पहुंच का प्रबंधन करें। यह प्रदर्शन को प्रभावित करने की क्षमता रखता है।

https://msdn.microsoft.com/en-us/library/ms186775(v=sql.105).aspx https://msdn.microsoft.com/en-us/library/ms186775(v=sql10
.10) .aspx


मुझे लगता है कि अंतराल मेरी प्राथमिक समस्या नहीं है - मेरी मुख्य समस्या मूल्यों की दृश्यता है। (यानी, कहते हैं, पहचान मूल्य 7 पहचान मूल्य 6 से पहले उस मूल्य से ऑर्डर करने वाले किसी प्रश्न के लिए अवलोकन योग्य नहीं होना चाहिए।)
फैबियन श्मिट

1
मैंने पहचान मूल्यों को देखा है जैसे: 1, 2, 5, 3, 4.
stacylaray

बेशक, यह आसानी से प्रतिलिपि प्रस्तुत करने योग्य है, उदाहरण के लिए, लेनार्ट के उत्तर से परिदृश्य का उपयोग करना। मैं जिस सवाल से जूझ रहा हूं, वह यह है कि क्या मैं एक खंड के साथ एक प्रश्न का उपयोग करते समय उस प्रतिबद्ध आदेश का पालन कर सकता हूं ORDER BY CheckpointSequence(जो क्लस्टर्ड इंडेक्स का क्रम होता है)। मुझे लगता है कि यह इस सवाल से उब जाता है कि क्या आइडेंटिटी वैल्यू की पीढ़ी किसी भी तरह से INSERT स्टेटमेंट द्वारा लिए गए तालों से जुड़ी हुई है, या यदि ये SQL सर्वर द्वारा एक के बाद एक किए गए दो असंबंधित कार्य हैं।
फेबियन श्मिड ने

1
प्रश्न क्या है? अगर पढ़े हुए प्रतिबद्ध का उपयोग कर रहे हैं, तो आपके उदाहरण में, क्रम 1, 2, 3, 5 दिखाएगा क्योंकि वे प्रतिबद्ध हो गए हैं और 4 नहीं, यानी गंदा पढ़ा है। इसके अलावा, NEventStore की आपकी व्याख्या "इसलिए, यह महत्वपूर्ण है कि घटनाओं को कभी भी छोड़ा नहीं जा सकता है, क्योंकि वे फिर कभी नहीं होंगे।"
स्टैसिलराय

क्वेरी ऊपर दी गई है ( gist.github.com/fschmied/47f716c32cb64b852f90 ) - यह पृष्ठांकित है, लेकिन एक साधारण से उबलता है SELECT ... FROM Commits WHERE CheckpointSequence > ... ORDER BY CheckpointSequence। मुझे नहीं लगता कि यह क्वेरी लॉक रो 4 को पढ़ेगी, या यह होगा? (मेरे प्रयोगों में, यह तब अवरुद्ध हो जाता है जब क्वेरी पंक्ति 4 के लिए कुंजी लॉक को प्राप्त करने की कोशिश करती है)
फाबियन श्मिड

1

मुझे संदेह है कि यह कभी-कभी परेशानी, मुसीबतों का कारण बन सकता है जब सर्वर भारी लोड के तहत खराब हो जाता है। दो लेनदेन पर विचार करें:

  1. T1: T में डालें ... - कहते हैं कि 5 डालें
  2. T2: T में डालें ... - कहते हैं कि 6 डालें
  3. टी 2: प्रतिबद्ध
  4. रीडर 6 नहीं बल्कि 5 देखता है
  5. टी 1: प्रतिबद्ध

उपरोक्त परिदृश्य में आपका LAST_READ_ID 6 होगा, इसलिए 5 कभी नहीं पढ़ा जाएगा।


मेरे परीक्षणों से संकेत मिलता है कि यह परिदृश्य समस्या नहीं है क्योंकि रीडर (चरण 4) ब्लॉक करेगा (जब तक कि T1 ने अपने ताले जारी नहीं किए हैं) जब यह मान के साथ पंक्ति को पढ़ने की कोशिश करता है 5. क्या मुझे कुछ याद आ रहा है?
फेबियन श्मिड

आप सही हो सकते हैं, मैं SQL सर्वर में लॉकिंग तंत्र को अच्छी तरह से नहीं जानता (इसलिए मुझे अपने उत्तर में संदेह है)।
लेनार्ट

पाठक के अलगाव स्तर पर निर्भर करता है। यह मेरे दोनों को देखता है, ब्लॉक करता है, या केवल 6. देखता है
माइकल ग्रीन

0

इस स्क्रिप्ट को चलाना:

BEGIN TRAN;
INSERT INTO dbo.Example DEFAULT VALUES;
COMMIT;

नीचे वे ताले हैं जिन्हें मैंने अधिग्रहीत किया है और विस्तारित इवेंट सत्र द्वारा कब्जा कर लिया गया है:

name            timestamp                   associated_object_id    mode    object_id   resource_type   session_id  resource_description
lock_acquired   2016-03-29 06:37:28.9968693 1585440722              IX      1585440722  OBJECT          51          
lock_acquired   2016-03-29 06:37:28.9969268 7205759890195415040     IX      0           PAGE            51          1:1235
lock_acquired   2016-03-29 06:37:28.9969306 7205759890195415040     RI_NL   0           KEY             51          (ffffffffffff)
lock_acquired   2016-03-29 06:37:28.9969330 7205759890195415040     X       0           KEY             51          (29cf3326f583)
lock_released   2016-03-29 06:37:28.9969579 7205759890195415040     X       0           KEY             51          (29cf3326f583)
lock_released   2016-03-29 06:37:28.9969598 7205759890195415040     IX      0           PAGE            51          1:1235
lock_released   2016-03-29 06:37:28.9969607 1585440722              IX      1585440722  OBJECT          51      

नई पंक्ति को बनाए जाने के लिए X कुंजी लॉक से ठीक पहले अधिग्रहीत RI_N KEY लॉक पर ध्यान दें। यह अल्पकालिक सीमा लॉक एक समवर्ती आवेषण को RI_N के अन्य लॉक को प्राप्त करने से रोकेगा क्योंकि RI_N लॉक असंगत हैं। चरण 2 और 3 के बीच जिस विंडो का आपने उल्लेख किया है, वह चिंता का विषय नहीं है क्योंकि रेंज लॉक को नई जनरेट की पर पंक्ति लॉक से पहले अधिग्रहित किया जाता है।

जब तक आपकी SELECT...ORDER BYवांछित वांछित नव-सम्मिलित पंक्तियों से पहले स्कैन शुरू हो जाता है, तब तक मैं आपसे डिफ़ॉल्ट READ COMMITTEDआइसोलेशन स्तर में वांछित व्यवहार की अपेक्षा करूंगा, जब तक कि डेटाबेस READ_COMMITTED_SNAPSHOTविकल्प बंद न हो जाए।


1
Technet.microsoft.com/en-us/library/… के अनुसार , दो ताले संगतRangeI_N होते हैं , यानी, एक दूसरे को ब्लॉक नहीं करते हैं (ताला ज्यादातर एक मौजूदा क्रमिक रीडर पर अवरुद्ध करने के लिए है)।
फेबियन श्मिड

@FabianSchmied, दिलचस्प। वह विषय Technet.microsoft.com/en-us/library/ms186396(v=sql.105).aspx में लॉक कम्पैटिबिलिटी मैट्रिक्स के साथ टकराव करता है , जो दिखाता है कि लॉक संगत नहीं हैं। आपके द्वारा बताए गए लिंक में इन्सर्ट उदाहरण वही व्यवहार करता है जैसा कि मेरे उत्तर में ट्रेस में दिखाया गया है (एक्सक्लूसिव की लॉक से पहले रेंज का परीक्षण करने के लिए अल्पकालिक इन्सर्ट रेंज लॉक)।
डैन गुज़मैन

1
दरअसल, मैट्रिक्स "एन" को "नो संघर्ष" के लिए कहता है ("संगत नहीं" के लिए) :)
फेबियन शिमिड

0

SQL सर्वर की मेरी समझ से डिफ़ॉल्ट व्यवहार दूसरी क्वेरी के लिए है जब तक कि पहली क्वेरी नहीं हुई है तब तक कोई परिणाम प्रदर्शित नहीं किया जाता है। यदि पहली क्वेरी COMMIT के बजाय एक ROLLBACK करती है, तो आपके कॉलम में एक गुम आईडी होगी।

मूल विन्यास

डेटाबेस तालिका

मैंने निम्नलिखित संरचना के साथ एक डेटाबेस तालिका बनाई:

CREATE TABLE identity_rc_test (
    ID4VALUE INT IDENTITY (1,1), 
    TEXTVALUE NVARCHAR(20),
    CONSTRAINT PK_ID4_VALUE_CLUSTERED 
        PRIMARY KEY CLUSTERED (ID4VALUE, TEXTVALUE)
)

डेटाबेस अलगाव स्तर

मैंने निम्नलिखित विवरण के साथ अपने डेटाबेस के अलगाव स्तर की जाँच की:

SELECT snapshot_isolation_state, 
       snapshot_isolation_state_desc, 
       is_read_committed_snapshot_on
FROM sys.databases WHERE NAME = 'mydatabase'

जो मेरे डेटाबेस के लिए निम्न परिणाम लौटाए:

snapshot_isolation_state    snapshot_isolation_state_desc   is_read_committed_snapshot_on
0                           OFF                             0

(यह SQL Server 2012 में डेटाबेस के लिए डिफ़ॉल्ट सेटिंग है)

टेस्ट लिपियों

निम्न स्क्रिप्ट्स को मानक SQL सर्वर SSMS क्लाइंट सेटिंग्स और मानक SQL सर्वर सेटिंग्स का उपयोग करके निष्पादित किया गया था।

क्लाइंट कनेक्शन सेटिंग्स

ग्राहक को READ COMMITTEDSSMS में क्वेरी विकल्प के अनुसार लेन-देन अलगाव स्तर का उपयोग करने के लिए निर्धारित किया गया है ।

प्रश्न 1

निम्न क्वेरी को SPID 57 के साथ क्वेरी विंडो में निष्पादित किया गया था

SELECT * FROM dbo.identity_rc_test
BEGIN TRANSACTION [FIRST_QUERY]
INSERT INTO dbo.identity_rc_test (TEXTVALUE) VALUES ('Nine')
/* Commit is commented out to prevent the INSERT from being commited
--COMMIT TRANSACTION [FIRST_QUERY]
--ROLLBACK TRANSACTION [FIRST_QUERY]
*/

प्रश्न २

निम्न क्वेरी को SPID 58 के साथ क्वेरी विंडो में निष्पादित किया गया था

BEGIN TRANSACTION [SECOND_QUERY]
INSERT INTO dbo.identity_rc_test (TEXTVALUE) VALUES ('Ten')
COMMIT TRANSACTION [SECOND_QUERY]
SELECT * FROM dbo.identity_rc_test

क्वेरी पूर्ण नहीं होती है और किसी पृष्ठ पर रिलीज़ होने के लिए eXclusive लॉक की प्रतीक्षा कर रही है।

लॉकिंग का निर्धारण करने के लिए स्क्रिप्ट

यह स्क्रिप्ट दो लेन-देन के लिए डेटाबेस ऑब्जेक्ट्स पर होने वाली लॉकिंग को प्रदर्शित करती है:

SELECT request_session_id, resource_type,
       resource_description, 
       resource_associated_entity_id,
       request_mode, request_status
FROM sys.dm_tran_locks
WHERE request_session_id IN (57, 58)

और यहाँ परिणाम हैं:

58  DATABASE                    0                   S   GRANT
57  DATABASE                    0                   S   GRANT
58  PAGE            1:79        72057594040549300   IS  GRANT
57  PAGE            1:79        72057594040549300   IX  GRANT
57  KEY         (a0aba7857f1b)  72057594040549300   X   GRANT
58  KEY         (a0aba7857f1b)  72057594040549300   S   WAIT
58  OBJECT                      245575913           IS  GRANT
57  OBJECT                      245575913           IX  GRANT

परिणाम बताते हैं कि क्वेरी विंडो एक (SPID 57) में OBJECT पर एक इरादा eXlusive (IX) लॉक के लिए एक साझा लॉक (S) है, जिस पेज पर एक eXclusive सम्मिलित करना चाहता है, उस पर एक एकीकृत eXlusive (IX) लॉक है। कुंजी पर लॉक (X) इसे डाला गया है, लेकिन अभी तक प्रतिबद्ध नहीं है।

अनकम्युरेटेड डेटा के कारण, दूसरी क्वेरी (SPID 58) में DATABASE स्तर पर एक साझा लॉक (S) है, OJJECT पर एक इंटेस्टेड शेयर्ड (IS) लॉक, एक साझा साझा (IS) पृष्ठ पर साझा किया गया लॉक (S) ) एक अनुरोध स्थिति WAIT के साथ कुंजी पर ताला।

सारांश

पहली क्वेरी विंडो में क्वेरी बिना किए निष्पादित होती है। क्योंकि दूसरी क्वेरी केवल उस READ COMMITTEDडेटा का इंतजार कर सकती है जब तक कि टाइमआउट न हो जाए या पहले क्वैरी में ट्रांजेक्शन न हो जाए।

यह Microsoft SQL सर्वर के डिफ़ॉल्ट व्यवहार को समझने से है।

आपको यह देखना चाहिए कि पहले कथन COMMIT होने पर ID वास्तव में बाद में पढ़े गए कथनों के क्रम में होता है।

यदि पहला बयान एक रोलबैक करता है, तो आपको अनुक्रम में एक लापता आईडी मिलेगा, लेकिन फिर भी आरोही क्रम में आईडी के साथ (बशर्ते आपने आईडी कॉलम पर डिफ़ॉल्ट या एएससी विकल्प के साथ INDEX बनाया हो)।

अद्यतन करें:

(स्पष्ट रूप से) हां, आप पहचान स्तंभ पर सही ढंग से काम कर सकते हैं, जब तक कि आप एक समस्या का सामना न करें। SQL Server 2000 और Microsoft की वेबसाइट पर पहचान कॉलम के बारे में केवल एक HOTFIX है

यदि आप पहचान स्तंभ पर सही तरीके से अपडेट करने पर भरोसा नहीं कर सकते, तो मुझे लगता है कि Microsoft की वेबसाइट पर अधिक हॉटफ़िक्स या पैच होंगे।

यदि आपके पास Microsoft समर्थन अनुबंध है, तो आप हमेशा एक सलाहकार मामला खोल सकते हैं और अतिरिक्त जानकारी के लिए पूछ सकते हैं।


1
विश्लेषण के लिए धन्यवाद, लेकिन मेरा सवाल यह है कि क्या अगली पीढ़ी की पीढ़ी Identityऔर पंक्ति पर प्रमुख लॉक के अधिग्रहण के बीच एक समय खिड़की है (जहां समवर्ती रीडर्स / लेखक गिर सकते हैं)। मुझे नहीं लगता कि यह आपकी टिप्पणियों से असंभव साबित होता है क्योंकि कोई भी उस अल्ट्रा-शॉर्ट टाइम विंडो के दौरान क्वेरी निष्पादन को रोक नहीं सकता है और ताले का विश्लेषण नहीं कर सकता है।
फेबियन श्मिड

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

1
एक सामान्य आधार पर, आपकी टिप्पणियां मेरे खुद के (और मेरी उम्मीदों से भी) मेल खाती हैं - यह जानना अच्छा है। मुझे आश्चर्य है कि अगर वहाँ असाधारण स्थिति है, जहां वे पकड़ नहीं होगा, हालांकि।
फाबियन ने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.