SQL Server 2008 R2 Leituras sujas - quão atômicas?

11

Estou me perguntando "quão suja" leituras sujas podem ficar sob um nível de isolamento não-lido . Entendo que as linhas que foram atualizadas, mas ainda não confirmadas, são visíveis, mas:

  1. Uma linha pode aparecer como parcialmente atualizada - ou seja, algumas das colunas são atualizadas e outras não?
  2. Uma única coluna pode aparecer parcialmente atualizada. Por exemplo, se você tiver uma coluna varchar (4000) que estava em processo de atualização completa e supondo que ela realmente contenha 4000 caracteres. Você pode ler, digamos, 2k caracteres do estado anterior e 2k caracteres do seu novo estado? E o varchar (max) com comprimento> 8k?

Atualização: Após alguns debates, o consenso mínimo é que, se o tamanho da coluna for> 8 KB, leituras sujas, mesmo dentro da própria coluna, serão possíveis.

Michael Goldshteyn
fonte

Respostas:

7

EDITADO depois de ler o link do fórum do MSDN no comentário , muito interessante.

Independentemente do nível de isolamento, dois usuários não podem atualizar uma única página simultaneamente, nem podem ler uma página parcialmente atualizada. Imagine como o SQL Server lidaria com uma página em que o cabeçalho diz Col3 começa no byte 17. Mas ele realmente começa no byte 25, porque essa parte da linha ainda não foi atualizada. Não há como um banco de dados lidar com isso.

Porém, para linhas maiores que 8k, várias páginas são usadas e isso possibilita uma coluna semi-atualizada. Copiado do link do MSDN (caso o link seja interrompido), inicie esta consulta em uma janela:

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

Isso cria uma tabela e a atualiza com uma sequência de 100.000x o mesmo caractere. Enquanto a primeira consulta estiver em execução, inicie-a em outra janela:

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

A segunda consulta para quando lê uma coluna que está parcialmente atualizada. Ou seja, quando o primeiro caractere é diferente do último. Ele terminará rapidamente, provando que é possível ler colunas semi-atualizadas. Se você remover a nolockdica, a segunda consulta nunca será concluída.

Resultado surpreendente! Uma coluna XML semi-atualizada pode quebrar um (nolock)relatório, porque o XML estaria malformado.

Andomar
fonte
1
Aparentemente, isso nem sempre é verdade, de acordo com social.msdn.microsoft.com/Forums/en-US/transactsql/thread/… , mas que tipos de coluna podem ser vistos parcialmente atualizados ainda é um mistério.
As travas do @Andomar AFAIK impediriam leituras de uma página parcialmente atualizada, mas e se alguns valores de coluna fossem lidos de uma NCI, mas fizesse uma pesquisa de marcador para recuperar uma coluna do IC. Em NOLOCKTenho certeza de que seria possível projetar uma situação em que as colunas da NCI fossem de uma versão da linha, mas o IC de uma versão diferente. Além disso, os dados fora de linha e as páginas lob não seriam protegidos pela trava na página de dados.
Martin Smith
1
@ Martin: Concordo, eu já vi uma auto-união com nolocknão encontrar sua linha original. No entanto, uma única leitura de um campo ou linha deve ser consistente.
Andomar 13/03
1
@Andomar, a menos que as colunas na linha abranjam várias páginas. Veja meu link.
2
Realmente deveria ser CW, porque a resposta original não estava nem perto da direita, Michael forneceu a essência da resposta atual. Seu comentário sobre a pergunta ainda não concorda com a resposta editada.