SQL Server 2008 R2 Брудне читає - як неатомний?


11

Мені цікаво, "як брудні" брудні читання можуть потрапити під рівень незахищеного читання . Я розумію, що рядки, які були оновлені, але ще не виконані, видно, але:

  1. Чи може рядок відображатися як частково оновлений - тобто деякі стовпці оновлюються, а деякі - ні?
  2. Чи може з’явитися окремий стовпець частково оновленим. Наприклад, якщо у вас стовпчик varchar (4000), який був повністю оновлений, і припускаючи, що він фактично містить 4000 символів. Чи можете ви прочитати скажімо 2k символів від попереднього стану та 2k символів з його нового стану? Що з варчаром (макс.) Довжиною> 8 к?

Оновлення: Після деяких дебатів мінімальний консенсус полягає в тому, що якщо розмір стовпця становить> 8 КБ, можливі брудні читання навіть у самій колонці.

Відповіді:


7

ВІДМОВЛЕНО після прочитання посилання на форум MSDN з коментаря , дуже цікаво.

Незалежно від рівня ізоляції, два користувачі не можуть одночасно оновлювати одну сторінку , а також жоден користувач не може прочитати частково оновлену сторінку. Уявіть собі, як SQL Server поводитиметься зі сторінкою, де заголовок каже, що Col3 починається з байту 17. Але він дійсно починається з байту 25, оскільки ця частина рядка ще не оновлена. База даних не може це впоратися.

Але для рядків, більших за 8 к, використовується кілька сторінок, і це робить можливим наполовину оновлений стовпець. Скопійовано із посилання 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
@Martin: Погоджено, я бачив, що самоз'єднання nolockне знайде свого початкового рядка. Однак одне читання поля чи рядка повинно бути послідовним.
Андомар

1
@Andomar, якщо стовпці в рядку не охоплюють кілька сторінок. Дивіться моє посилання.

2
Це дійсно має бути CW, тому що оригінальна відповідь ніде не була правильною, Майкл надав суть поточної відповіді. Ваш коментар проти запитання все ще не згідний з відредагованою відповіддю.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.