किसी तालिका में अंतिम पहचान सम्मिलित करने का सर्वोत्तम तरीका


35

एक डालने के माध्यम से मैंने जो पहचान मूल्य प्राप्त किया है, वह सबसे अच्छा विकल्प कौन सा है? प्रदर्शन के संदर्भ में इन बयानों का क्या प्रभाव है?

  1. SCOPE_IDENTITY()
  2. समुच्चय समारोह MAX()
  3. चयन TOP 1IdentityColumn TableName सेORDER BY IdentityColumn DESC

1
PostgreSQL का प्रयोग करें और आपके पास यह शेल्फ़ postgresql.org/docs/9.1/static/sql-insert.html से होगा
येवगेनी अफ़ानासिएव

लेफ्टफील्ड विकल्प - यदि आपके पास तालिका में एक दिशा-निर्देश स्तंभ है और आप एक नई मार्गदर्शिका उत्पन्न कर सकते हैं और इसे सम्मिलित करने के दौरान नए कॉलम में सम्मिलित कर सकते हैं - तो आप जनरेटेड इंटेस्ट आइडेंटिटी को बाहर निकालने के लिए उस गाइड के साथ पंक्ति का चयन कर सकते हैं।
निको

जवाबों:


56

SCOPE_IDENTITY()यदि आप एकल पंक्ति सम्मिलित कर रहे हैं, तो उपयोग करें और जो आईडी जनरेट की गई थी, उसे पुनः प्राप्त करना चाहते हैं।

CREATE TABLE #a(identity_column INT IDENTITY(1,1), x CHAR(1));

INSERT #a(x) VALUES('a');

SELECT SCOPE_IDENTITY();

परिणाम:

----
1

OUTPUTयदि आप कई पंक्तियाँ सम्मिलित कर रहे हैं, तो क्लॉज़ का उपयोग करें और उत्पन्न आईडी के सेट को पुनः प्राप्त करने की आवश्यकता है ।

INSERT #a(x) 
  OUTPUT inserted.identity_column 
  VALUES('b'),('c');

परिणाम:

----
2
3

और यह सबसे अच्छा विकल्प क्यों है?

एक तरफ प्रदर्शन, ये वही हैं जो डिफ़ॉल्ट अलगाव स्तर और / या कई उपयोगकर्ताओं के साथ सही होने की गारंटी है। भले ही आप शुद्धता के पहलू को अनदेखा करते हों, लेकिन SQL सर्वर सम्मिलित मूल्य रखता हैSCOPE_IDENTITY() स्मृति , इसलिए स्वाभाविक रूप से यह टेबल के खिलाफ या सिस्टम तालिकाओं के खिलाफ अपने स्वयं के पृथक क्वेरी को चलाने और चलाने की तुलना में तेज़ होगा।

शुद्धता के पहलू को नजरअंदाज करना मेलमैन को यह बताने जैसा है कि उसने आज के मेल को डिलीवर करने का अच्छा काम किया है - उसने अपना रूट अपने औसत समय से 10 मिनट तेजी से पूरा किया, समस्या यह है कि मेल में से कोई भी सही घर पर नहीं दिया गया था।

निम्नलिखित में से किसी का उपयोग करें:

  • @@IDENTITY - चूंकि यह सभी परिदृश्यों में उपयोग नहीं किया जा सकता है, उदाहरण के लिए जब एक पहचान स्तंभ के साथ एक तालिका में एक ट्रिगर होता है जो अपने स्वयं के पहचान कॉलम के साथ किसी अन्य तालिका में सम्मिलित करता है - आपको गलत मान वापस मिलेगा।
  • IDENT_CURRENT()- मैं यहां इसके बारे में विस्तार से जाता हूं , और टिप्पणियों के साथ-साथ उपयोगी पढ़ना भी है, लेकिन अनिवार्य रूप से, संगामिति के तहत, आपको अक्सर गलत जवाब मिलेगा।
  • MAX()या TOP 1- आपको यह सुनिश्चित करने के लिए क्रमबद्ध रूप से अलग-थलग के साथ दो बयानों की रक्षा करनी होगी ताकि आपको यह पता चले कि MAX()आप किसी और के नहीं हैं। यह सिर्फ उपयोग करने की तुलना में बहुत अधिक महंगा है SCOPE_IDENTITY()

जब भी आप दो या अधिक पंक्तियों को सम्मिलित करते हैं, तो ये फ़ंक्शन विफल हो जाते हैं, और उत्पन्न सभी पहचान मूल्यों की आवश्यकता होती है - आपका एकमात्र विकल्प OUTPUTखंड है।


मेरी याद में एक और सवाल शुरू हो गया। जब कभी भी हमें किसी विशेष सत्र में अंतिम पहचान प्राप्त करने की आवश्यकता होती है, तो किसी भी सत्र या उपयोगकर्ता का एकमात्र और सबसे अच्छा तरीका उस कॉलम का MAX () होता है?
AA.SC

जब मैं एक तालिका में कई पंक्तियाँ डालूंगा तो SCOPE_IDENTITY () हमेशा अंतिम जनरेट की गई पहचान कैसे लौटाएगा? यदि स्तंभ प्राथमिक कुंजी है, लेकिन पहचान स्तंभ नहीं है तो क्या होगा?
AA.SC

@ AA.SC हाँ, यह अंतिम एक लौटाएगा। यदि यह कोई पहचान स्तंभ नहीं है, तो नहीं, इनमें से कोई भी कार्य नहीं करेगा। उस मामले में पीके मूल्य कहां से आता है?
आरोन बर्ट्रेंड

मैंने इसे हमारे आवेदन में एक कॉलम के लिए देखा है जहां कॉलम INT प्रकार का है, और डेवलपर्स MAX (कॉलमनाम) +1 का उपयोग करते हैं, जब कभी भी उन्हें एक नया रिकॉर्ड सम्मिलित करने की आवश्यकता होती है
AA.SC

तब उन्हें पहले से ही पता होता है कि उन्होंने क्या मूल्य डाला है। SQL सर्वर के पास आपको यह बताने का कोई तरीका नहीं है कि (आप इस तथ्य के बाद MAX को फिर से खींचने पर भरोसा नहीं कर सकते, जब तक कि आपने अपने पूरे लेन-देन को पूरी तरह से अलग नहीं कर लिया हो, जो प्रदर्शन या संगामिति के लिए अच्छा नहीं होगा)।
आरोन बर्ट्रेंड

7

प्रदर्शन के अलावा, उनके पास सभी अलग-अलग अर्थ हैं।

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

IDENT_CURRENT()आप से एक विशिष्ट तालिका में सम्मिलित पिछले पहचान मूल्य दे देंगे किसी भी , गुंजाइश द्वारा किसी भी उपयोगकर्ता ।

@@IDENTITYटेबल या स्कोप की परवाह किए बिना, आपको वर्तमान कनेक्शन के लिए सबसे हाल के INSERT स्टेटमेंट द्वारा उत्पन्न अंतिम पहचान मूल्य प्रदान करता है। (साइड नोट: एक्सेस इस फ़ंक्शन का उपयोग करता है, और इस प्रकार ट्रिगर्स के साथ कुछ समस्याएँ हैं जो पहचान स्तंभों के साथ तालिकाओं में मान सम्मिलित करते हैं।)

यदि तालिका में नकारात्मक पहचान चरण है, या खेलने के साथ पंक्तियाँ डाली गई हैं, तो उपयोग करना MAX()या TOP 1आपको पूरी तरह से गलत परिणाम दे सकता है SET IDENTITY_INSERT। इन सभी को प्रदर्शित करने वाली एक स्क्रिप्ट यहां दी गई है:

CREATE TABLE ReverseIdent (
    id int IDENTITY(9000,-1) NOT NULL PRIMARY KEY CLUSTERED,
    data char(4)
)

INSERT INTO ReverseIdent (data)
VALUES ('a'), ('b'), ('c')

SELECT * FROM ReverseIdent

SELECT IDENT_CURRENT('ReverseIdent') --8998
SELECT MAX(id) FROM ReverseIdent --9000

SET IDENTITY_INSERT ReverseIdent ON

INSERT INTO ReverseIdent (id, data)
VALUES (9005, 'd')

SET IDENTITY_INSERT ReverseIdent OFF

SELECT IDENT_CURRENT('ReverseIdent') --8998
SELECT MAX(id) FROM ReverseIdent --9005

सारांश: छड़ी के साथ SCOPE_IDENTITY(), IDENT_CURRENT()या @@IDENTITY, और सुनिश्चित करें कि आप उस का उपयोग कर रहे हैं जो आपको वास्तव में जरूरत है जो वापस लौटाता है।


1
आप अपने उपयोग को प्रोत्साहित क्यों करते हैं IDENT_CURRENT()और @@IDENTITYजब आपकी स्वयं की स्क्रिप्ट दर्शाती है कि वे गलत परिणाम देते हैं?
हारून बर्ट्रेंड

1
@AaronBertrand मुझे यकीन नहीं है कि मैं अनुसरण करता हूं। उत्पन्न अंतिम पहचान मूल्य 8998 था (ध्यान दें कि चरण -1 है), और यही IDENT_CURRENT()रिटर्न है। MAX () पहली पंक्ति से परे सही मान कभी नहीं लौटाता है, क्योंकि आईडी पीछे की ओर गिनती कर रही है, और इसके साथ IDENTITY_INSERT, 9005 एक उत्पन्न पहचान मूल्य नहीं है, इस प्रकार से परिलक्षित नहीं होता है IDENT_CURRENT()। लेकिन यह हो सकता है लौटने "गलत" परिणाम यदि आप के बाद क्या वास्तव में कर रहे हैं SCOPE_IDENTITY()रिटर्न। नौकरी के लिए सही उपकरण चुनें।
db2

ओपी को लगता है कि उनके द्वारा डाले गए पहचान मूल्य के बाद - इस मामले में 8998 गलत है। आपके द्वारा उल्लिखित एज केस (बैकवर्ड इन्क्रीमेंट और IDENTITY_INSERT पर) मेरी राय में IDENT_CURRENT का उपयोग करने के खिलाफ और भी तर्क देते हैं , और @@ IDENTITY का उपयोग वास्तव में ट्रिगर्स (अब या बाद में जोड़े जाने) के खतरे के कारण नहीं किया जाना चाहिए। मैं अभी भी यह समझने के लिए संघर्ष कर रहा हूं कि क्यों IDENT_CURRENT वह होगा जो ओपी उपयोग करना चाहेगा (विशेष रूप से संक्षिप्त के तहत) या क्यों @@ पहचान का उपयोग कभी भी किसी के द्वारा किया जाएगा जब बहुत अधिक विश्वसनीय तरीके मौजूद होंगे।
हारून बर्ट्रेंड

@AaronBertrand इस सवाल से 100% स्पष्ट नहीं है कि वांछित परिणाम वर्तमान गुंजाइश से अंतिम प्रविष्टि है (उस संबंध में विकल्प 1 2 और 3 से अलग है), इसलिए मुझे लगा कि यह दोनों का वर्णन करने के लिए एक अच्छा विचार होगा और वे कैसे भिन्न होते हैं। लेकिन मैं मानता हूं कि @@IDENTITYउत्पन्न पहचान मूल्यों को प्राप्त करने का आदर्श तरीका लगभग नहीं है। मुख्य बिंदु यह है कि MAX()या TOP 1एक कम विश्वसनीय संस्करण की IDENT_CURRENT()तरह है, जो कि यदि आप समझते हैं कि यह क्या करता है, का उपयोग करने के लिए एक पूरी तरह से ठीक कार्य है। रखरखाव नौकरियों या कुछ के लिए उपयोगी हो सकता है।
db2
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.