9.5 और नया:
PostgreSQL 9.5 और नया समर्थन INSERT ... ON CONFLICT UPDATE
(और ON CONFLICT DO NOTHING
), अर्थात।
के साथ तुलनाON DUPLICATE KEY UPDATE
।
त्वरित स्पष्टीकरण ।
उपयोग के लिए मैनुअल को देखें - विशेष रूप से सिंटैक्स आरेख और व्याख्यात्मक पाठ में परस्पर विरोधी खंड ।
9.4 और पुराने के समाधान के विपरीत, जो नीचे दिए गए हैं, यह सुविधा कई परस्पर विरोधी पंक्तियों के साथ काम करती है और इसके लिए अनन्य लॉकिंग या रिट्री लूप की आवश्यकता नहीं होती है।
फीचर को जोड़ने के लिए प्रतिबद्ध है और इसके विकास के चारों ओर चर्चा यहाँ है ।
यदि आप 9.5 पर हैं और आपको पिछड़े-संगत होने की आवश्यकता नहीं है तो आप अभी पढ़ना बंद कर सकते हैं ।
9.4 और पुराने:
PostgreSQL में कोई अंतर्निहित UPSERT
(या MERGE
) सुविधा नहीं है, और इसे समवर्ती उपयोग के चेहरे में कुशलतापूर्वक करना बहुत मुश्किल है।
यह लेख उपयोगी विस्तार से समस्या पर चर्चा करता है ।
सामान्य तौर पर आपको दो विकल्पों के बीच चयन करना होगा:
- रिट्रीट लूप में अलग-अलग इंसर्ट / अपडेट ऑपरेशन; या
- टेबल लॉक करना और बैच मर्ज करना
व्यक्तिगत पंक्ति पुनः लूप
यदि आप कई कनेक्शन सम्मिलित रूप से आवेषण करने की कोशिश कर रहे हैं, तो एक रिट्री लूप में अलग-अलग पंक्ति अपस्कर्ट का उपयोग करना उचित विकल्प है।
PostgreSQL प्रलेखन में एक उपयोगी प्रक्रिया है जो आपको डेटाबेस के अंदर लूप में ऐसा करने देगी । यह ज्यादातर भोले समाधानों के विपरीत, खोए हुए अपडेट और रस्सियों को सम्मिलित करता है। यह केवल में काम करेगाREAD COMMITTED
मोड और केवल सुरक्षित है यदि यह एकमात्र ऐसा कार्य है जो आप लेनदेन में करते हैं, हालांकि। यदि ट्रिगर या द्वितीयक अनन्य कुंजियाँ अनूठे उल्लंघन का कारण बनती हैं तो फ़ंक्शन सही ढंग से काम नहीं करेगा।
यह रणनीति बहुत अक्षम है। जब भी व्यावहारिक हो आपको काम को कतारबद्ध करना चाहिए और इसके बजाय नीचे बताए गए अनुसार एक थोक अपटाउन करना चाहिए।
इस समस्या के कई हल किए गए समाधान रोलबैक पर विचार करने में विफल होते हैं, इसलिए उनके परिणामस्वरूप अपूर्ण अपडेट होते हैं। एक दूसरे के साथ दो लेनदेन दौड़; उनमें से एक सफलतापूर्वक INSERT
; दूसरे को एक डुप्लिकेट कुंजी त्रुटि मिलती है और UPDATE
इसके बजाय करता है । UPDATE
ब्लॉक के लिए इंतज़ार कर INSERT
रोलबैक या प्रतिबद्ध करने के लिए। जब यह वापस आ जाता है, तो UPDATE
हालत फिर से जाँच शून्य पंक्तियों से मेल खाती है, इसलिए भले ही UPDATE
यह वास्तव में आपके द्वारा अपेक्षित अपेक्षा को पूरा नहीं करता है। आपको परिणाम पंक्ति की गणना की जांच करनी होगी और जहां आवश्यक हो वहां पुन: प्रयास करना होगा।
कुछ प्रयास किए गए समाधान भी SELECT दौड़ पर विचार करने में विफल होते हैं। यदि आप स्पष्ट और सरल कोशिश करते हैं:
-- THIS IS WRONG. DO NOT COPY IT. It's an EXAMPLE.
BEGIN;
UPDATE testtable
SET somedata = 'blah'
WHERE id = 2;
-- Remember, this is WRONG. Do NOT COPY IT.
INSERT INTO testtable (id, somedata)
SELECT 2, 'blah'
WHERE NOT EXISTS (SELECT 1 FROM testtable WHERE testtable.id = 2);
COMMIT;
तब जब दो बार एक साथ कई विफलता मोड होते हैं। अपडेट री-चेक के साथ पहले से ही चर्चा की गई समस्या है। एक और जहां दोनों UPDATE
एक ही समय में, शून्य पंक्तियों से मेल खाते हैं और जारी रखते हैं। फिर वे दोनों EXISTS
परीक्षण करते हैं, जो पहले होता है INSERT
। दोनों को शून्य पंक्तियाँ मिलती हैं, इसलिए दोनों करते हैंINSERT
। एक डुप्लिकेट कुंजी त्रुटि के साथ विफल रहता है।
यही कारण है कि आपको फिर से कोशिश करने वाले लूप की आवश्यकता है। आप सोच सकते हैं कि आप स्मार्ट SQL के साथ डुप्लिकेट कुंजी त्रुटियों या खो अद्यतन को रोक सकते हैं, लेकिन आप नहीं कर सकते। आपको पंक्ति गणना की जांच करने या डुप्लिकेट कुंजी त्रुटियों (चुने हुए दृष्टिकोण के आधार पर) और फिर से प्रयास करने की आवश्यकता है।
कृपया इसके लिए अपना समाधान न रोल करें। संदेश की कतार के साथ की तरह, यह शायद गलत है।
ताला के साथ उखाड़ फेंकना
कभी-कभी आप एक बल्क अपर्चर करना चाहते हैं, जहां आपके पास एक नया डेटा सेट होता है जिसे आप पुराने मौजूदा डेटा सेट में मर्ज करना चाहते हैं। यह अलग-अलग पंक्ति के उत्थान की तुलना में बहुत अधिक कुशल है और जब भी व्यावहारिक हो, इसे प्राथमिकता दी जानी चाहिए।
इस स्थिति में, आप आमतौर पर निम्नलिखित प्रक्रिया का पालन करते हैं:
CREATE
एक TEMPORARY
मेज
COPY
या अस्थायी तालिका में नया डेटा सम्मिलित करें
LOCK
लक्ष्य तालिका IN EXCLUSIVE MODE
। यह अन्य लेन-देन की अनुमति देता है SELECT
, लेकिन तालिका में कोई बदलाव नहीं करता है।
एक है UPDATE ... FROM
अस्थायी तालिका में मानों का उपयोग मौजूदा रिकॉर्ड की;
एक है INSERT
पंक्तियों को पहले से ही लक्ष्य तालिका में मौजूद नहीं है की;
COMMIT
, ताला जारी।
उदाहरण के लिए, प्रश्न में दिए गए उदाहरण के लिए, INSERT
अस्थायी तालिका को आबाद करने के लिए बहु-मूल्य का उपयोग करना:
BEGIN;
CREATE TEMPORARY TABLE newvals(id integer, somedata text);
INSERT INTO newvals(id, somedata) VALUES (2, 'Joe'), (3, 'Alan');
LOCK TABLE testtable IN EXCLUSIVE MODE;
UPDATE testtable
SET somedata = newvals.somedata
FROM newvals
WHERE newvals.id = testtable.id;
INSERT INTO testtable
SELECT newvals.id, newvals.somedata
FROM newvals
LEFT OUTER JOIN testtable ON (testtable.id = newvals.id)
WHERE testtable.id IS NULL;
COMMIT;
संबंधित पढ़ने
व्हाट अबाउट MERGE
?
एसक्यूएल मानक MERGE
वास्तव में खराब संगोष्ठी को परिभाषित करता है और पहले एक तालिका को लॉक किए बिना उखाड़ने के लिए उपयुक्त नहीं है।
यह डेटा मर्जिंग के लिए एक बहुत ही उपयोगी OLAP स्टेटमेंट है, लेकिन यह वास्तव में संगामिति-सुरक्षित शोधकर्ता के लिए उपयोगी समाधान नहीं है। अन्य DBMSes का उपयोग करने वाले लोगों को उपयोग करने के लिए बहुत सारी सलाह हैMERGE
, लेकिन यह वास्तव में गलत है।
अन्य DBs: