संबंधित उत्तर में आप इसका उल्लेख कर रहे हैं:
- अद्यतन पोस्ट करता है ... सीमा 1
इसका उद्देश्य एक . को लॉक करना है एक समय में पंक्ति। यह एडवाइजरी लॉक के साथ या उसके बिना ठीक काम करता है, क्योंकि डेडलॉक की कोई संभावना नहीं है - जब तक आप एक ही लेन-देन में अधिक पंक्तियों को लॉक करने का प्रयास नहीं करते हैं।
आपका उदाहरण इस मायने में अलग है कि आप एक बार में 3000 पंक्तियों को लॉक करना चाहते हैं . वहाँ है गतिरोध के लिए संभावित, सिवाय इसके कि सभी समवर्ती लेखन संचालन एक ही सुसंगत क्रम में पंक्तियों को लॉक करते हैं। प्रति दस्तावेज़:
<ब्लॉकक्वॉट>डेडलॉक के खिलाफ सबसे अच्छा बचाव आम तौर पर यह सुनिश्चित करके है कि डेटाबेस का उपयोग करने वाले सभी एप्लिकेशन एक ही क्रम में कई ऑब्जेक्ट्स पर लॉक प्राप्त करते हैं।
इसे अपनी सबक्वेरी में ORDER BY के साथ लागू करें।
UPDATE cargo_item item
SET job_id = 'SOME_UUID', job_ts = now()
FROM (
SELECT id
FROM cargo_item
WHERE state='NEW' AND job_id is null
ORDER BY id
LIMIT 3000
FOR UPDATE
) sub
WHERE item.id = sub.id;
यह तब तक सुरक्षित और विश्वसनीय है, जब तक सभी लेन-देन उसी क्रम में लॉक प्राप्त करते हैं और ऑर्डरिंग कॉलम के समवर्ती अपडेट की अपेक्षा नहीं की जाती है। (मैनुअल में इस अध्याय के अंत में पीला "सावधानी" बॉक्स पढ़ें।) तो यह आपके मामले में सुरक्षित होना चाहिए, क्योंकि आप id
को अपडेट नहीं करने जा रहे हैं। कॉलम।
प्रभावी रूप से एक समय में केवल एक क्लाइंट इस तरह से पंक्तियों में हेरफेर कर सकता है। समवर्ती लेनदेन समान (लॉक) पंक्तियों को लॉक करने का प्रयास करेंगे और पहले लेनदेन के समाप्त होने की प्रतीक्षा करेंगे।
सलाहकार ताले उपयोगी हैं यदि आपके पास कई या बहुत लंबे समय तक चलने वाले समवर्ती लेनदेन हैं (ऐसा नहीं लगता कि आप करते हैं)। केवल कुछ के साथ, केवल उपरोक्त क्वेरी का उपयोग करना और समवर्ती लेनदेन को अपनी बारी की प्रतीक्षा करना समग्र रूप से सस्ता होगा।
सभी एक अद्यतन में
ऐसा लगता है कि समवर्ती पहुंच आपके सेटअप में प्रति समस्या नहीं है। Concurrency आपके वर्तमान समाधान द्वारा बनाई गई एक समस्या है।
इसके बजाय, इसे एक ही UPDATE
में करें . n
. के बैच असाइन करें प्रत्येक यूयूआईडी के लिए संख्या (उदाहरण में 3000) और सभी को एक साथ अपडेट करें। सबसे तेज़ होना चाहिए।
UPDATE cargo_item c
SET job_id = u.uuid_col
, job_ts = now()
FROM (
SELECT row_number() OVER () AS rn, uuid_col
FROM uuid_tbl WHERE <some_criteria> -- or see below
) u
JOIN (
SELECT (row_number() OVER () / 3000) + 1 AS rn, item.id
FROM cargo_item
WHERE state = 'NEW' AND job_id IS NULL
FOR UPDATE -- just to be sure
) c2 USING (rn)
WHERE c2.item_id = c.item_id;
प्रमुख बिंदु
-
पूर्णांक विभाजन छोटा हो जाता है। आपको पहली 3000 पंक्तियों के लिए 1, अगली 3000 पंक्तियों के लिए 2 मिलता है। आदि.
-
मैं मनमाने ढंग से पंक्तियों को चुनता हूं, आप
ORDER BY
लागू कर सकते हैं विंडो मेंrow_number()
. के लिए कुछ पंक्तियों को निर्दिष्ट करने के लिए। -
यदि आपके पास प्रेषण के लिए UUIDs की तालिका नहीं है (
uuid_tbl
), एकVALUES
. का उपयोग करें उन्हें आपूर्ति करने के लिए अभिव्यक्ति। उदाहरण। -
आपको 3000 पंक्तियों के बैच मिलते हैं। यदि आपको असाइन करने के लिए 3000 का गुणज नहीं मिलता है, तो अंतिम बैच 3000 से कम होगा।