SQL Server 2008 R2 डर्टी पढ़ता है - गैर-परमाणु कैसे?


11

मैं सोच रहा हूं कि "कितना गंदा" गंदे रीड्स पढ़े-अनछुए अलगाव स्तर के तहत प्राप्त कर सकते हैं । मैं समझता हूं कि जो पंक्तियां अपडेट की गई हैं लेकिन अभी तक प्रतिबद्ध नहीं हैं वे दिखाई दे रही हैं, लेकिन:

  1. क्या एक पंक्ति आंशिक रूप से अद्यतन के रूप में दिखाई दे सकती है - अर्थात, कुछ कॉलम अपडेट किए गए हैं और कुछ नहीं हैं?
  2. क्या कोई एकल स्तंभ आंशिक रूप से अद्यतन दिखाई दे सकता है। उदाहरण के लिए, यदि आपके पास एक varchar (4000) कॉलम है जो पूरी तरह से अपडेट होने और इसे वास्तव में 4000 वर्णों के मानने की प्रक्रिया में था। क्या आप पिछले राज्य से 2k वर्ण और उसके नए राज्य से 2k वर्ण पढ़ सकते हैं? लंबाई> 8k के साथ varchar (अधिकतम) के बारे में क्या?

अद्यतन: कुछ बहस के बाद, न्यूनतम आम सहमति यह है कि यदि स्तंभ का आकार> 8KB है, तो गंदे रीड्स, यहां तक ​​कि कॉलम के भीतर भी संभव है।

जवाबों:


7

संपादित पढ़ने के बाद टिप्पणी से MSDN मंच लिंक , बहुत ही दिलचस्प।

अलगाव स्तर के बावजूद, दो उपयोगकर्ता एक साथ एक पृष्ठ को अपडेट नहीं कर सकते हैं, और न ही कोई उपयोगकर्ता आंशिक रूप से अपडेट किए गए पृष्ठ को पढ़ सकता है। जरा सोचिए कि SQL सर्वर उस पेज से कैसे निपटेगा जहां हेडर कहता है कि Col3 बाइट 17 से शुरू होता है। लेकिन यह वास्तव में बाइट 25 से शुरू होता है, क्योंकि पंक्ति का वह हिस्सा अभी तक अपडेट नहीं किया गया है। कोई तरीका नहीं है कि एक डेटाबेस को संभाल सकता है।

लेकिन 8k से बड़ी पंक्तियों के लिए, कई पृष्ठों का उपयोग किया जाता है, और यह आधे-अपडेट किए गए कॉलम को संभव बनाता है। MSDN लिंक से लिंक किया गया (लिंक टूटने की स्थिति में), इस क्वेरी को एक विंडो में शुरू करें:

if object_id('TestTable') is not null
    drop table TestTable
create table TestTable (txt nvarchar(max) not null)
go
insert into TestTable select replicate(convert(varchar(max),
    char(65+abs(checksum(newid()))%26)),100000)
go 10
update TestTable set txt=replicate(convert(varchar(max),
    char(65+abs(checksum(newid()))%26)),100000)
go 100000

यह एक तालिका बनाता है और फिर इसे उसी वर्ण के 100.000x स्ट्रिंग के साथ अद्यतन करता है। जबकि पहली क्वेरी चल रही है, इस क्वेरी को किसी अन्य विंडो में प्रारंभ करें:

while 1=1 begin
 if exists (select * from TestTable (nolock) where left(Txt,1) <> right(Txt,1))
    break
end

दूसरी क्वेरी तब बंद हो जाती है जब वह एक कॉलम पढ़ता है जो आधा अपडेट होता है। अर्थात्, जब पहला वर्ण पिछले से अलग होता है। यह जल्दी से खत्म हो जाएगा, यह साबित करते हुए कि आधे अपडेट किए गए कॉलम को पढ़ना संभव है। यदि आप nolockसंकेत निकालते हैं, तो दूसरी क्वेरी कभी समाप्त नहीं होगी।

आश्चर्यजनक परिणाम! एक अर्ध-अद्यतन XML स्तंभ एक (nolock)रिपोर्ट तोड़ सकता है , क्योंकि XML विकृत हो जाएगा।


1
यह जाहिरा तौर पर हमेशा सच नहीं होता है, प्रति social.msdn.microsoft.com/Forums/en-US/transactsql/thread/… , लेकिन स्तंभ प्रकारों को आंशिक रूप से अपडेट किया जा सकता है जो अभी भी कुछ हद तक रहस्य है।

@Andomar AFAIK कुंडी आंशिक रूप से अपडेट किए गए पृष्ठ को पढ़ने से रोकती है लेकिन क्या होगा यदि कुछ स्तंभ मान NCI से पढ़े जाते हैं लेकिन यह CI से एक कॉलम को पुनः प्राप्त करने के लिए एक बुकमार्क लुकअप करता है। के तहत NOLOCKमुझे यकीन है कि यह एक ऐसी स्थिति में इंजीनियर करना संभव होगा जहां NCI कॉलम पंक्ति के एक संस्करण से थे लेकिन CI एक अलग संस्करण से। इसके अतिरिक्त रो डेटा और लॉब पेज डेटा पेज पर कुंडी द्वारा संरक्षित नहीं होंगे।
मार्टिन स्मिथ

1
@ मॉर्टिन: सहमत, मैंने nolockअपनी मूल पंक्ति को नहीं ढूंढने के साथ एक स्वयं को शामिल किया है । हालांकि, एक क्षेत्र या पंक्ति का एक एकल पाठ सुसंगत होना चाहिए।
एंडोमर

1
@Andomar, जब तक पंक्ति में कॉलम कई पृष्ठों पर नहीं होता। मेरा लिंक देखें

2
यह वास्तव में सीडब्ल्यू होना चाहिए क्योंकि मूल उत्तर कहीं निकट नहीं था, माइकल ने वर्तमान उत्तर का सार प्रदान किया। सवाल के खिलाफ आपकी टिप्पणी अभी भी संपादित जवाब से सहमत नहीं है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.