अनुक्रमों में समवर्ती सम्मिलन की अनुमति देने के लिए अंतराल हैं। अंतराल से बचने या हटाए गए आईडी का पुन:उपयोग करने का प्रयास भयानक प्रदर्शन समस्याएं पैदा करता है। PostgreSQL विकी अक्सर पूछे जाने वाले प्रश्न देखें।
PostgreSQL SEQUENCE
s का उपयोग आईडी आवंटित करने के लिए किया जाता है। ये केवल कभी बढ़ते हैं, और उन्हें एक ही समय में नई आईडी हथियाने के लिए कई लेनदेन की अनुमति देने के लिए सामान्य लेनदेन रोलबैक नियमों से छूट दी गई है। इसका अर्थ यह है कि यदि कोई लेन-देन वापस ले लिया जाता है, तो उन आईडी को "फेंक दिया जाता है"; "मुफ्त" आईडी की कोई सूची नहीं है, बस वर्तमान आईडी काउंटर है। यदि डेटाबेस अशुद्ध रूप से बंद हो जाता है तो अनुक्रम भी आमतौर पर बढ़ जाते हैं।
सिंथेटिक कुंजियाँ (आईडी) अर्थहीन हैं फिर भी। उनका क्रम महत्वपूर्ण नहीं है, उनके महत्व की एकमात्र संपत्ति विशिष्टता है। आप अर्थपूर्ण रूप से यह नहीं माप सकते कि दो आईडी कितनी "दूर" हैं, और न ही आप सार्थक रूप से कह सकते हैं कि एक आईडी दूसरे से बड़ी है या कम। आप बस इतना कर सकते हैं कि "बराबर" या "बराबर नहीं" कहें। और कुछ भी असुरक्षित है। आपको अंतराल की परवाह नहीं करनी चाहिए।
यदि आपको एक अंतराल रहित अनुक्रम की आवश्यकता है जो हटाए गए आईडी का पुन:उपयोग करता है, तो आपके पास एक हो सकता है, आपको बस इसके लिए बड़ी मात्रा में प्रदर्शन छोड़ना होगा - विशेष रूप से, आपके पास INSERT
पर कोई समरूपता नहीं हो सकती है बिल्कुल भी, क्योंकि आपको सबसे कम मुफ्त आईडी के लिए तालिका को स्कैन करना होगा, लिखने के लिए तालिका को लॉक करना होगा ताकि कोई अन्य लेनदेन समान आईडी का दावा न कर सके। "postgresql गैपलेस सीक्वेंस" खोजने की कोशिश करें।
काउंटर टेबल और अगली आईडी प्राप्त करने वाले फ़ंक्शन का उपयोग करना सबसे आसान तरीका है। यहां एक सामान्यीकृत संस्करण है जो लगातार अंतराल रहित आईडी उत्पन्न करने के लिए काउंटर टेबल का उपयोग करता है; हालांकि, यह आईडी का पुन:उपयोग नहीं करता है।
CREATE TABLE thetable_id_counter ( last_id integer not null );
INSERT INTO thetable_id_counter VALUES (0);
CREATE OR REPLACE FUNCTION get_next_id(countertable regclass, countercolumn text) RETURNS integer AS $$
DECLARE
next_value integer;
BEGIN
EXECUTE format('UPDATE %s SET %I = %I + 1 RETURNING %I', countertable, countercolumn, countercolumn, countercolumn) INTO next_value;
RETURN next_value;
END;
$$ LANGUAGE plpgsql;
COMMENT ON get_next_id(countername regclass) IS 'Increment and return value from integer column $2 in table $1';
उपयोग:
INSERT INTO dummy(id, blah)
VALUES ( get_next_id('thetable_id_counter','last_id'), 42 );
ध्यान दें कि जब एक खुले लेन-देन ने एक आईडी प्राप्त की है, तो अन्य सभी लेन-देन जो get_next_id
को कॉल करने का प्रयास करते हैं तब तक ब्लॉक रहेगा जब तक कि पहला ट्रांजैक्शन नहीं हो जाता या वापस रोल नहीं हो जाता। यह अपरिहार्य है और गैपलेस आईडी के लिए और डिजाइन के अनुसार है।
यदि आप एक तालिका में विभिन्न उद्देश्यों के लिए कई काउंटरों को स्टोर करना चाहते हैं, तो बस उपरोक्त फ़ंक्शन में एक पैरामीटर जोड़ें, काउंटर टेबल में एक कॉलम जोड़ें, और एक WHERE
जोड़ें। UPDATE
का खंड जो जोड़े गए कॉलम के पैरामीटर से मेल खाता है। इस तरह आपके पास कई स्वतंत्र रूप से बंद काउंटर पंक्तियाँ हो सकती हैं। नहीं करें नए काउंटरों के लिए बस अतिरिक्त कॉलम जोड़ें।
यह फ़ंक्शन हटाए गए आईडी का पुन:उपयोग नहीं करता है, यह केवल अंतराल को पेश करने से बचाता है।
आईडी का पुन:उपयोग करने के लिए मैं सलाह देता हूं ... आईडी का पुन:उपयोग न करें।
यदि आपको वास्तव में जरूरी है, तो आप ON INSERT OR UPDATE OR DELETE
जोड़कर ऐसा कर सकते हैं। रुचि की तालिका पर ट्रिगर करें जो हटाए गए आईडी को एक फ्री-लिस्ट साइड टेबल में जोड़ता है, और उन्हें फ्री-लिस्ट टेबल से हटा देता है जब वे INSERT
होते हैं ईडी। एक UPDATE
का इलाज करें DELETE
के रूप में उसके बाद INSERT
. अब ऊपर दिए गए आईडी जनरेशन फ़ंक्शन को संशोधित करें ताकि यह SELECT free_id INTO next_value FROM free_ids FOR UPDATE LIMIT 1
और यदि पाया जाता है, तो DELETE
एस वह पंक्ति। IF NOT FOUND
सामान्य रूप से जनरेटर तालिका से एक नई आईडी प्राप्त करता है। पुन:उपयोग का समर्थन करने के लिए यहां पिछले फ़ंक्शन का परीक्षण न किया गया एक्सटेंशन है:
CREATE OR REPLACE FUNCTION get_next_id_reuse(countertable regclass, countercolumn text, freelisttable regclass, freelistcolumn text) RETURNS integer AS $$
DECLARE
next_value integer;
BEGIN
EXECUTE format('SELECT %I FROM %s FOR UPDATE LIMIT 1', freelistcolumn, freelisttable) INTO next_value;
IF next_value IS NOT NULL THEN
EXECUTE format('DELETE FROM %s WHERE %I = %L', freelisttable, freelistcolumn, next_value);
ELSE
EXECUTE format('UPDATE %s SET %I = %I + 1 RETURNING %I', countertable, countercolumn, countercolumn, countercolumn) INTO next_value;
END IF;
RETURN next_value;
END;
$$ LANGUAGE plpgsql;