SQL Server 2008 R2 Dirty อ่านแล้ว - ไม่ใช่อะตอมอย่างไร?


11

ฉันสงสัยว่า "การอ่านที่สกปรก" สกปรกแค่ไหนนั้นสามารถอยู่ภายใต้ระดับการแยกแบบไม่ต้องอ่านได้ ฉันเข้าใจว่าแถวที่ได้รับการปรับปรุงแล้วแต่ยังไม่ได้มีการยืนยันจะปรากฏให้เห็น แต่:

  1. แถวสามารถปรากฏเป็นอัปเดตบางส่วนได้หรือไม่นั่นคือบางคอลัมน์มีการอัปเดตและบางคอลัมน์ไม่ได้
  2. คอลัมน์เดียวสามารถปรากฏการปรับปรุงบางส่วน ตัวอย่างเช่นถ้าคุณมีคอลัมน์ varchar (4000) ที่อยู่ในกระบวนการของการปรับปรุงอย่างสมบูรณ์และสมมติว่ามันมี 4,000 ตัวอักษร คุณสามารถอ่านพูดว่า 2k chars จากสถานะก่อนหน้าและ 2k chars จากสถานะใหม่ได้หรือไม่? แล้ว varchar (สูงสุด) ที่มีความยาว> 8k

อัปเดต: หลังจากมีการโต้วาทีความเห็นร่วมขั้นต่ำคือถ้าขนาดคอลัมน์> 8KB ผู้อ่านสกปรกแม้อยู่ในคอลัมน์ก็เป็นไปได้

คำตอบ:


7

แก้ไขหลังจากอ่านลิงก์ฟอรัม MSDN จากความคิดเห็นน่าสนใจมาก

ผู้ใช้สองคนไม่สามารถอัปเดตหน้าเดียวพร้อมกันโดยไม่คำนึงถึงระดับการแยกผู้ใช้ไม่สามารถอ่านเพจที่อัปเดตบางส่วนได้ แค่คิดว่า SQL Server จะจัดการกับหน้าเว็บที่ส่วนหัวบอกว่า 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 latches จะป้องกันการอ่านหน้าเว็บที่ได้รับการปรับปรุงบางส่วน แต่จะทำอย่างไรถ้าค่าคอลัมน์บางค่าถูกอ่านจาก NCI แต่ทำการค้นหาบุ๊กมาร์กเพื่อดึงคอลัมน์จาก CI ภายใต้NOLOCKฉันแน่ใจว่าจะเป็นไปได้ที่จะสร้างสถานการณ์ที่คอลัมน์ NCI มาจากรุ่นหนึ่งของแถว แต่ CI จากรุ่นอื่น การปิดข้อมูลแถวและหน้า lob จะไม่ได้รับการปกป้องโดย latch บนหน้าข้อมูล
Martin Smith

1
@ มาร์ติน: เห็นด้วยฉันเห็นตัวเองเข้าร่วมด้วยnolockไม่พบแถวเดิม อย่างไรก็ตามการอ่านเขตข้อมูลหรือแถวเดียวควรสอดคล้องกัน
Andomar

1
@Andomar ยกเว้นว่าคอลัมน์ในแถวจะขยายหลายหน้า ดูลิงค์ของฉัน

2
นี่ควรเป็น CW จริง ๆ เพราะคำตอบดั้งเดิมไม่มีที่อยู่ใกล้ที่สุด Michael ให้ส่วนสำคัญของคำตอบปัจจุบัน ความคิดเห็นของคุณที่มีต่อคำถามยังคงไม่เห็นด้วยกับคำตอบที่แก้ไข
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.