पहचान कॉलम में अप्रत्याशित अंतराल


18

मैं 1 से शुरू होने वाले अद्वितीय खरीद ऑर्डर नंबर उत्पन्न करने की कोशिश कर रहा हूं और 1 से वृद्धि कर रहा हूं। मेरे पास इस स्क्रिप्ट का उपयोग करके एक PONumber टेबल बनाई गई है:

CREATE TABLE [dbo].[PONumbers]
(
  [PONumberPK] [int] IDENTITY(1,1) NOT NULL,
  [NewPONo] [bit] NOT NULL,
  [DateInserted] [datetime] NOT NULL DEFAULT GETDATE(),
  CONSTRAINT [PONumbersPK] PRIMARY KEY CLUSTERED ([PONumberPK] ASC)    
);

और इस स्क्रिप्ट का उपयोग करके बनाई गई एक संग्रहीत प्रक्रिया:

CREATE PROCEDURE [dbo].[GetPONumber] 
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO [dbo].[PONumbers]([NewPONo]) VALUES(1);
    SELECT SCOPE_IDENTITY() AS PONumber;
END

निर्माण के समय, यह ठीक काम करता है। जब संग्रहीत प्रक्रिया चलती है, तो यह वांछित संख्या में शुरू होता है और 1 से बढ़ जाता है।

अजीब बात यह है कि, अगर मैं अपने कंप्यूटर को बंद या हाइबरनेट करता हूं, तो अगली बार जब प्रक्रिया चलती है, तो अनुक्रम लगभग 1000 तक आगे बढ़ गया है।

नीचे देखें परिणाम:

पीओ नंबर

आप देख सकते हैं कि संख्या 8 से 1002 तक उछल गई!

  • ये क्यों हो रहा है?
  • मैं यह कैसे सुनिश्चित करूं कि नंबर उस तरह से स्किप न हों?
  • SQL के लिए सभी की आवश्यकता है कि संख्याएँ उत्पन्न करें:
    • क) अद्वितीय गारंटी।
    • ख) वांछित राशि से वृद्धि।

मैं मानता हूँ कि मैं एक SQL विशेषज्ञ नहीं हूँ। क्या मुझे गलत समझ है कि SCOPE_IDENTITY () क्या करता है? क्या मुझे एक अलग दृष्टिकोण का उपयोग करना चाहिए? मैंने SQL 2012+ में अनुक्रमों में देखा, लेकिन Microsoft का कहना है कि वे डिफ़ॉल्ट रूप से अद्वितीय होने की गारंटी नहीं हैं।

जवाबों:


25

यह एक ज्ञात और अपेक्षित मुद्दा है - जिस तरह से SQL सर्वर द्वारा प्रबंधित की जाने वाली पहचान कॉलम SQL सर्वर 2012 ( कुछ पृष्ठभूमि ) में बदल गया है ; डिफ़ॉल्ट रूप से यह 1000 मानों को कैश करेगा और यदि आप SQL सर्वर को पुनरारंभ करते हैं, तो सर्वर को रिबूट करें, विफल रहें, आदि इसके लिए उन 1000 मानों को बाहर फेंकना होगा, क्योंकि यह जानने का एक विश्वसनीय तरीका नहीं होगा कि उनमें से कितने वास्तव में थे जारी किया गया। यह यहाँ प्रलेखित है । एक ट्रेस ध्वज है जो इस व्यवहार को बदलता है जैसे कि हर IDENTITY असाइनमेंट * लॉग किया गया है, जो उन विशिष्ट अंतराल को रोकता है (लेकिन रोलबैक या डिलीट से अंतराल नहीं); हालांकि, यह ध्यान रखना महत्वपूर्ण है कि प्रदर्शन के मामले में यह काफी महंगा हो सकता है, इसलिए मैं यहां विशिष्ट ट्रेस ध्वज का उल्लेख करने वाला नहीं हूं।

* (व्यक्तिगत रूप से, मुझे लगता है कि यह एक तकनीकी समस्या है जिसे अलग तरीके से हल किया जा सकता है, लेकिन जब से मैं इंजन नहीं लिखता, मैं इसे बदल नहीं सकता।)

इस बात के बारे में स्पष्ट होना कि IDENTITY और SEQUENCE कैसे काम करते हैं:

  • अद्वितीय होने की गारंटी नहीं है (आपको प्राथमिक कुंजी या अद्वितीय बाधा का उपयोग करके तालिका स्तर पर इसे लागू करने की आवश्यकता है)
  • न तो गैपलेस होने की गारंटी है (कोई भी रोलबैक या डिलीट, उदाहरण के लिए, एक गैप उत्पन्न करेगा, यह विशिष्ट समस्या चाहे जो भी हो)

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

इस "समस्या" पर बहुत सारी पृष्ठभूमि:


यह उत्तर ("ट्रेस ध्वज" भाग को छोड़कर) अधिकांश अन्य एसक्यूएल डेटाबेस (जो कि वैसे भी अनुक्रम हैं) पर भी लागू होता है।
17-29 में मस्टीको जूल

जवाब के लिए धन्यवाद। विशिष्टता सबसे महत्वपूर्ण आवश्यकता है। अंतराल एक बड़ी बात नहीं है, जब तक कि वे बड़े नहीं होते हैं। उदाहरण के लिए 1 से 4 तक जाना स्वीकार्य होगा, लेकिन 4 से 1003 तक नहीं होगा।
एज़ एर्सोज़

1
लघु संस्करण: आईडी मानों का उपयोग खरीद क्रम संख्याओं के रूप में किया जाएगा। ग्राहक मासिक रिपोर्ट चलाता है और जल्दी से यह बताना चाहता है कि पीओ नंबर को देखकर ही उस महीने कितने PO जमा किए गए थे। इसलिए हम इसे ~ 1000 से बढ़ा नहीं सकते हैं (एक साप्ताहिक रखरखाव है जहां सभी सर्वर, DB सर्वर सहित, पुनः आरंभ होते हैं)।
ईज एर्सोज़

3
आप उन्हें एक बहुत ही आसान रिपोर्ट क्यों नहीं देते हैं जो सिर्फ ROW_NUMBER () OVER (PARTITION BY Month ORDER BY ID) का उपयोग करती है? फिर से, आईडी नंबर अर्थहीन होना चाहिए, यह एक भयानक तरीका है कि नेत्रगोलक को कितने आदेश दिए गए थे। क्या होगा यदि आपके पास अपने कोड में एक बग है जो 1000 पंक्तियों को हटाता है या 275 लेनदेन को वापस करता है, या 500 ऑर्डर वैध रूप से रद्द किए जाते हैं?
हारून बर्ट्रेंड

1
@Ege: "... बताओ कितने ... सिर्फ PO नंबर देखकर"। आपके उपयोगकर्ता निराश होने वाले हैं। पहचान मान बस इस तरह से काम नहीं करते हैं, न ही आपको (या उन्हें) ऐसी कोई धारणा बनानी चाहिए। अद्वितीय? हाँ। लगातार? नहीं। एक महीने के दौरान पीओ के प्रस्तुत किए गए गणना करने का सही तरीका है ... प्रत्येक रिकॉर्ड में कुछ [अप्राप्य] दिनांक फ़ील्ड के आधार पर उस महीने के दौरान पीओ की संख्या की गणना करना।
फिलिप्स डब्ल्यू।

-4

यह SQL Server की समस्या है। आप केवल इतना कर सकते हैं कि कॉलम को फिर से लिखा जाए।

गलत कॉलम आईडी वाली प्रविष्टियों को हटाएं। स्तंभ की पहचान का विश्लेषण किया। और फिर अगली प्रविष्टि में इसके लिए उचित आईडी है।

निम्नलिखित आज्ञाचक्र का उपयोग करते हुए Reseed पहचान: DBCC CHECKIDENT ('YOUR_TABLE_NAME', RESEED, 9)- 9 अंतिम सही Id है


1
"प्रविष्टियों को हटाएं" से आपका क्या अभिप्राय है?
ypercube y

2
हम्मम .. लगता है प्रविष्टियों को हटाने से डेटा हानि हो सकती है।
माइकल ग्रीन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.