सबसे आम समस्याओं में से एक जो समवर्ती लेनदेन चलाते समय होती है, वह है डर्टी रीड समस्या। एक गंदा पठन तब होता है जब एक लेनदेन को उस डेटा को पढ़ने की अनुमति दी जाती है जिसे दूसरे लेनदेन द्वारा संशोधित किया जा रहा है जो एक साथ चल रहा है लेकिन जिसने अभी तक खुद को प्रतिबद्ध नहीं किया है।
यदि डेटा को संशोधित करने वाला लेन-देन स्वयं होता है, तो गंदी पढ़ने की समस्या नहीं होती है। हालाँकि, यदि डेटा को संशोधित करने वाले लेन-देन को अन्य लेन-देन द्वारा डेटा पढ़ने के बाद वापस रोल किया जाता है, तो बाद वाले लेनदेन में गंदा डेटा होता है जो वास्तव में मौजूद नहीं होता है।
हमेशा की तरह, नए कोड के साथ प्रयोग करने से पहले सुनिश्चित करें कि आपने अच्छी तरह से बैकअप लिया है। यदि आप सुनिश्चित नहीं हैं तो MS SQL डेटाबेस के बैकअप पर यह लेख देखें।
इसे एक उदाहरण की मदद से समझते हैं। मान लीजिए कि हमारे पास 'उत्पाद' नाम की एक तालिका है जो उत्पाद के लिए आईडी, नाम और आइटम्सइनस्टॉक को संग्रहीत करती है।
तालिका इस तरह दिखती है:
[टेबल आईडी=20 /]
मान लीजिए कि आपके पास एक ऑनलाइन सिस्टम है जहां एक उपयोगकर्ता एक ही समय में उत्पादों को खरीद सकता है और उत्पादों को देख सकता है। निम्न आकृति पर एक नज़र डालें।
एक ऐसे परिदृश्य पर विचार करें जहां कोई उपयोगकर्ता किसी उत्पाद को खरीदने का प्रयास करता है। लेन-देन 1 उपयोगकर्ता के लिए खरीद कार्य करेगा। लेन-देन में पहला कदम ItemsinStock को अपडेट करना होगा।
लेन-देन से पहले, स्टॉक में 12 आइटम हैं; लेन-देन इसे 11 में अपडेट कर देगा। लेन-देन अब बाहरी बिलिंग गेटवे के साथ संचार करेगा।
यदि इस समय, एक और लेन-देन, मान लें कि लेन-देन 2, लैपटॉप के लिए ItemsInStock पढ़ता है, तो यह 11 पढ़ेगा। हालाँकि, यदि बाद में, लेन-देन 1 के पीछे उपयोगकर्ता के खाते में अपर्याप्त धनराशि पाई जाती है, तो लेन-देन 1 शुरू हो जाएगा। वापस और ItemsInStock कॉलम का मान 12 पर वापस आ जाएगा।
हालांकि, लेनदेन 2 में ItemsInStock कॉलम के मान के रूप में 11 है। यह गंदा डेटा है और इस समस्या को डर्टी रीड प्रॉब्लम कहा जाता है।
डर्टी रीड प्रॉब्लम का वर्किंग उदाहरण
आइए SQL सर्वर में कार्रवाई में गंदी पढ़ने की समस्या पर एक नज़र डालें। हमेशा की तरह, सबसे पहले, अपनी तालिका बनाएं और उसमें कुछ डमी डेटा जोड़ें। अपने डेटाबेस सर्वर पर निम्न स्क्रिप्ट निष्पादित करें।
CREATE DATABASE pos;
USE pos;
CREATE TABLE products
(
Id INT PRIMARY KEY,
Name VARCHAR(50) NOT NULL,
ItemsinStock INT NOT NULL
)
INSERT into products
VALUES
(1, 'Laptop', 12),
(2, 'iPhone', 15),
(3, 'Tablets', 10)
अब, दो SQL सर्वर प्रबंधन स्टूडियो इंस्टेंस को साथ-साथ खोलें। हम इनमें से प्रत्येक उदाहरण में एक लेन-देन चलाएंगे।
SSMS के पहले उदाहरण में निम्न स्क्रिप्ट जोड़ें।
USE pos;
SELECT * FROM products
-- Transaction 1
BEGIN Tran
UPDATE products set ItemsInStock = 11
WHERE Id = 1
-- Billing the customer
WaitFor Delay '00:00:10'
Rollback Transaction
उपरोक्त स्क्रिप्ट में, हम एक नया लेनदेन शुरू करते हैं जो उत्पाद तालिका के "आइटमइनस्टॉक" कॉलम के मूल्य को अपडेट करता है जहां आईडी 1 है। हम तब 'वेटफोर' और 'देरी' फ़ंक्शन का उपयोग करके ग्राहक को बिलिंग के लिए देरी का अनुकरण करते हैं। स्क्रिप्ट में 10 सेकेंड की देरी सेट की गई है। उसके बाद, हम केवल लेन-देन को वापस ले लेते हैं।
SSMS के दूसरे उदाहरण में, हम केवल निम्नलिखित SELECT स्टेटमेंट जोड़ते हैं।
USE pos;
-- Transaction 2
SELECT * FROM products
WHERE Id = 1
अब, पहले पहला लेन-देन चलाएं, यानी एसएसएमएस के पहले उदाहरण में स्क्रिप्ट निष्पादित करें, और फिर एसएसएमएस के दूसरे उदाहरण में तुरंत स्क्रिप्ट निष्पादित करें।
आप देखेंगे कि दोनों लेनदेन 10 सेकंड के लिए निष्पादित होते रहेंगे और उसके बाद, आप देखेंगे कि आईडी 1 के साथ रिकॉर्ड के लिए 'आइटमइनस्टॉक' कॉलम का मान अभी भी 12 है जैसा कि दूसरे लेनदेन में दिखाया गया है। हालांकि पहले लेन-देन ने इसे 11 में अपडेट किया, 10 सेकंड के लिए प्रतीक्षा की, और फिर इसे वापस 12 पर रोल किया, दूसरे लेन-देन द्वारा दिखाया गया मान 11 के बजाय 12 है।
वास्तव में क्या हुआ कि जब हमने पहला लेन-देन किया, तो उसने 'आइटम्सइनस्टॉक' कॉलम के लिए मूल्य को अपडेट किया। इसके बाद इसने 10 सेकंड तक प्रतीक्षा की और फिर लेन-देन को वापस ले लिया।
हालाँकि हमने पहले लेन-देन के तुरंत बाद दूसरा लेन-देन शुरू किया, लेकिन इसे पहले लेन-देन के पूरा होने की प्रतीक्षा करनी पड़ी। यही कारण है कि दूसरा लेनदेन भी 10 सेकंड के लिए इंतजार कर रहा था और पहला लेनदेन पूरा होने के तुरंत बाद दूसरा लेनदेन क्यों किया गया।
प्रतिबद्ध अलगाव स्तर पढ़ें
लेन-देन 2 को निष्पादित होने से पहले लेनदेन 1 के पूरा होने की प्रतीक्षा क्यों करनी पड़ी?
इसका उत्तर यह है कि लेन-देन के बीच डिफ़ॉल्ट अलगाव स्तर "पढ़ें प्रतिबद्ध" है। रीड कमिटेड आइसोलेशन स्तर यह सुनिश्चित करता है कि डेटा को केवल लेन-देन द्वारा पढ़ा जा सकता है यदि वह प्रतिबद्ध स्थिति में है।
हमारे उदाहरण में, लेन-देन 1 ने डेटा को अपडेट किया, लेकिन इसे तब तक प्रतिबद्ध नहीं किया जब तक इसे वापस रोल नहीं किया गया। यही कारण है कि लेन-देन 2 को डेटा को पढ़ने से पहले लेन-देन 1 के लिए प्रतीक्षा करनी पड़ी या लेन-देन को रोलबैक करना पड़ा।
अब, व्यावहारिक परिदृश्यों में, हमारे पास अक्सर एक ही समय में एक ही डेटाबेस पर कई लेन-देन होते हैं और हम नहीं चाहते कि प्रत्येक लेनदेन को अपनी बारी का इंतजार करना पड़े। यह डेटाबेस को बहुत धीमा बना सकता है। एक बड़ी वेबसाइट से ऑनलाइन कुछ खरीदने की कल्पना करें जो एक समय में केवल एक लेनदेन को संसाधित कर सके!
अनकमिटेड डेटा पढ़ना
इस समस्या का उत्तर आपके लेन-देन को अप्रतिबद्ध डेटा के साथ काम करने देना है।
अनकमिटेड डेटा को पढ़ने के लिए, लेन-देन के आइसोलेशन स्तर को "अनकमिटेड रीड" पर सेट करें। नीचे दी गई स्क्रिप्ट के अनुसार एक आइसोलेशन लेवल जोड़कर ट्रांजेक्शन 2 को अपडेट करें।
USE pos;
-- Transaction 2
set transaction isolation level read uncommitted
SELECT * FROM products
WHERE Id = 1
अब यदि आप ट्रांजेक्शन 1 चलाते हैं और फिर तुरंत ट्रांजेक्शन 2 चलाते हैं, तो आप देखेंगे कि ट्रांजेक्शन 2 डेटा कमिट करने के लिए ट्रांजेक्शन 1 की प्रतीक्षा नहीं करेगा। लेनदेन 2 तुरंत गंदा डेटा पढ़ेगा। यह निम्न आकृति में दिखाया गया है:
यहां बाईं ओर का उदाहरण लेन-देन 1 चल रहा है और दाईं ओर का उदाहरण लेनदेन 2 चल रहा है।
हम पहले लेन-देन 1 चलाते हैं जो आईडी 1 से 11 के लिए "आइटम्सइनस्टॉक" के मूल्य को 12 से अपडेट करता है और फिर वापस लुढ़कने से पहले 10 सेकंड तक प्रतीक्षा करता है।
इस बीच, लेन-देन w गंदे डेटा को पढ़ता है जो कि 11 है, जैसा कि दाईं ओर परिणाम विंडो में दिखाया गया है। क्योंकि लेन-देन 1 को वापस ले लिया गया है, यह तालिका में वास्तविक मान नहीं है। वास्तविक मान 12 है। लेन-देन 2 को फिर से निष्पादित करने का प्रयास करें और आप देखेंगे कि इस बार यह 12 प्राप्त करता है।
बिना पढ़े ही एकमात्र अलगाव स्तर है जिसमें गंदी पढ़ने की समस्या है। यह आइसोलेशन स्तर सभी आइसोलेशन स्तरों के लिए कम से कम प्रतिबंधात्मक है और अनकमिटेड डेटा को पढ़ने की अनुमति देता है।
जाहिर है, रीड अनकमिटेड का उपयोग करने के पक्ष और विपक्ष हैं, यह इस बात पर निर्भर करता है कि आपके डेटाबेस का उपयोग किस एप्लिकेशन के लिए किया जाता है। जाहिर है, एटीएम सिस्टम और अन्य बहुत सुरक्षित सिस्टम के पीछे डेटाबेस के लिए इसका इस्तेमाल करना बहुत बुरा विचार होगा। हालांकि, उन अनुप्रयोगों के लिए जहां गति बहुत महत्वपूर्ण है (बड़े ई-कॉमर्स स्टोर चलाना) रीड अनकमिटेड का उपयोग करना अधिक समझ में आता है।