आप स्कैन किए जाने वाले पूरे सेट में प्रति पंक्ति एक बार pg_try_advisory_lock() को कॉल कर रहे हैं (फ़िल्टरिंग के भाग के रूप में जो where
में होता है) क्लॉज), जबकि आप चाहते हैं कि इसे क्वेरी द्वारा लौटाए गए तालिका 1 में प्रति पंक्ति केवल एक बार कॉल किया जाए।
आप इसके बजाय एक सबक्वेरी या सीटीई का उपयोग करने का प्रयास कर सकते हैं:
with rows as (
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
)
select rows.*
from rows
where pg_try_advisory_lock('table1'::regclass::integer, rows.id);
लेकिन अपेक्षित रूप से काम करने के लिए उस पर भरोसा न करें:पोस्टग्रेज़ को इसे फिर से लिखने के लिए लुभाया जाना चाहिए जिस तरह से आपकी प्रारंभिक क्वेरी थी।
एक और संभावना यह है, क्योंकि select
किसी कथन के भाग का मूल्यांकन क्वेरी में बहुत देर से किया जाता है:
with rows as (
SELECT a.id,
pg_try_advisory_lock('table1'::regclass::integer, a.id) as locked
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
)
select rows.id
from rows
where rows.locked;
व्यवहार में वास्तविक समस्या यह है कि pg_try_advisory_lock()
ऐसा कुछ है जो आप आम तौर पर ऐप लैंड या किसी फ़ंक्शन में ढूंढते हैं, बजाय किसी क्वेरी के जैसे आप कर रहे हैं। जिसके बारे में बोलते हुए, आप जो कर रहे हैं उसके आधार पर, क्या आप सुनिश्चित हैं कि आपको select … for update
?
आपके अपडेट के संबंध में:
हाँ। limit 1
. के कारण , यह एक मैच खोजने जा रहा है और तुरंत रुक जाएगा। हालांकि, संभवत:जो हो रहा है, वह यह है कि यह where
का मूल्यांकन नहीं कर रहा है आपके प्रश्नों के आधार पर उसी क्रम में खंड। SQL इस बात की कोई गारंटी नहीं देता कि a <> 0
a <> 0 and b / a > c
. में भाग लें पहले मूल्यांकन किया जाता है। आपके मामले में लागू, यह कोई गारंटी नहीं देता है कि सलाहकार लॉक बाद . प्राप्त किया गया है a की पंक्ति b से जुड़ जाती है।