SQL Server 2008 R2 Dirty читает - как не атомно?

Мне интересно, как грязные «грязные» чтения могут попадать под уровень изоляции read-uncommited . Я понимаю, что строки, которые были обновлены, но еще не зафиксированы, видны, но:

  1. Может ли строка отображаться как частично обновленная, то есть некоторые из столбцов обновляются, а некоторые нет?
  2. Можно ли частично обновить один столбец. Например, если у вас есть столбец varchar (4000), который находится в процессе полного обновления, и предположим, что на самом деле он содержит 4000 символов. Можете ли вы прочитать 2k символов из предыдущего состояния и 2k символов из своего нового состояния? Как насчет varchar (max) с длиной> 8k?

Обновление. После некоторых обсуждений минимальный консенсус заключается в том, что если размер столбца равен> 8KB, могут использоваться грязные чтения, даже внутри самого столбца.

11 голосов | спросил Michael Goldshteyn 13 MarpmSun, 13 Mar 2011 16:34:42 +03002011-03-13T16:34:42+03:0004 2011, 16:34:42

1 ответ


7

EDITED после прочтения Сообщение форума 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 будет искажен.

ответил Andomar 13 MarpmSun, 13 Mar 2011 16:41:54 +03002011-03-13T16:41:54+03:0004 2011, 16:41:54

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132