मैं इस धारणा के तहत काम कर रहा हूं कि SQL सर्वर में एक ही स्टेटमेंट सुसंगत है
वह धारणा गलत है। निम्नलिखित दो लेन-देन में समान लॉकिंग सिमेंटिक हैं:
STATEMENT
BEGIN TRAN; STATEMENT; COMMIT
जरा भी फर्क नहीं। सिंगल स्टेटमेंट और ऑटो-कमिट कुछ भी नहीं बदलते हैं।
इसलिए सभी तर्कों को एक कथन में मिलाने से कोई मदद नहीं मिलती है (यदि ऐसा होता है, तो यह दुर्घटनावश था क्योंकि योजना बदल गई थी)।
आइए समस्या को हाथ में ठीक करें। SERIALIZABLE
आपके द्वारा देखी जा रही असंगति को ठीक कर देगा क्योंकि यह गारंटी देता है कि आपके लेन-देन ऐसा व्यवहार करते हैं जैसे कि उन्होंने सिंगल-थ्रेडेड रूप से निष्पादित किया हो। समान रूप से, वे ऐसा व्यवहार करते हैं जैसे उन्होंने तुरंत निष्पादित किया।
आपको गतिरोध मिल रहा होगा। यदि आप पुन:प्रयास लूप के साथ ठीक हैं, तो आप इस बिंदु पर कर चुके हैं।
यदि आप अधिक समय निवेश करना चाहते हैं, तो प्रासंगिक डेटा तक अनन्य पहुंच को बाध्य करने के लिए लॉकिंग संकेत लागू करें:
UPDATE Gifts -- U-locked anyway
SET GivenAway = 1
WHERE GiftID = (
SELECT TOP 1 GiftID
FROM Gifts WITH (UPDLOCK, HOLDLOCK) --this normally just S-locks.
WHERE g2.GivenAway = 0
AND (SELECT COUNT(*) FROM Gifts g2 WITH (UPDLOCK, HOLDLOCK) WHERE g2.GivenAway = 1) < 5
ORDER BY g2.GiftValue DESC
)
अब आप कम संगामिति देखेंगे। यह आपके लोड के आधार पर पूरी तरह से ठीक हो सकता है।
आपकी समस्या की प्रकृति ही समेकन को कठिन बना देती है। यदि आपको इसके समाधान की आवश्यकता है तो हमें और अधिक आक्रामक तकनीकों को लागू करने की आवश्यकता होगी।
आप अद्यतन को थोड़ा सरल कर सकते हैं:
WITH g AS (
SELECT TOP 1 Gifts.*
FROM Gifts
WHERE g2.GivenAway = 0
AND (SELECT COUNT(*) FROM Gifts g2 WITH (UPDLOCK, HOLDLOCK) WHERE g2.GivenAway = 1) < 5
ORDER BY g2.GiftValue DESC
)
UPDATE g -- U-locked anyway
SET GivenAway = 1
यह एक अनावश्यक जुड़ाव से छुटकारा दिलाता है।