SQL Server 2008 R2 Lecturas sucias: ¿cómo no atómico?

11

Me pregunto qué tan sucias pueden ser las lecturas sucias por debajo de un nivel de aislamiento de lectura no confirmada . Entiendo que las filas que se han actualizado pero que aún no se han confirmado son visibles, pero:

  1. ¿Puede una fila aparecer como parcialmente actualizada, es decir, algunas de las columnas se actualizan y otras no?
  2. ¿Puede una sola columna aparecer parcialmente actualizada? Por ejemplo, si tiene una columna varchar (4000) que estaba en proceso de actualizarse completamente y suponiendo que en realidad contiene 4000 caracteres. ¿Puedes leer decir 2k caracteres del estado anterior y 2k caracteres de su nuevo estado? ¿Qué pasa con varchar (max) con longitud> 8k?

Actualización: después de un debate, el consenso mínimo es que si el tamaño de la columna es> 8 KB, son posibles las lecturas sucias, incluso dentro de la columna misma.

Michael Goldshteyn
fuente

Respuestas:

7

EDITADO después de leer el enlace del foro de MSDN del comentario , muy interesante.

Independientemente del nivel de aislamiento, dos usuarios no pueden actualizar una sola página simultáneamente, ni ningún usuario puede leer una página parcialmente actualizada. Solo imagine cómo trataría SQL Server con una página donde el encabezado dice que Col3 comienza en el byte 17. Pero realmente comienza en el byte 25, porque esa parte de la fila aún no se ha actualizado. No hay forma de que una base de datos pueda manejar eso.

Pero para las filas de más de 8k, se utilizan varias páginas, y eso hace posible una columna a medio actualizar. Copiado del enlace MSDN (en caso de que el enlace se rompa), inicie esta consulta en una ventana:

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

Esto crea una tabla y luego la actualiza con una cadena de 100.000x el mismo carácter. Mientras se ejecuta la primera consulta, inicie esta consulta en otra ventana:

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

La segunda consulta se detiene cuando lee una columna que está medio actualizada. Es decir, cuando el primer personaje es diferente del último. Terminará rápidamente, lo que demuestra que es posible leer columnas medio actualizadas. Si elimina la nolockpista, la segunda consulta nunca finalizará.

Resultado sorprendente! Una columna XML a medio actualizar podría romper un (nolock)informe, porque el XML estaría mal formado.

Andomar
fuente
1
Aparentemente, esto no siempre es cierto, según social.msdn.microsoft.com/Forums/en-US/transactsql/thread/… , pero qué tipos de columnas se pueden ver parcialmente actualizados sigue siendo un misterio.
Los bloqueos de @Andomar AFAIK evitarían lecturas de una página parcialmente actualizada, pero ¿qué pasaría si algunos valores de columna se leyeran de un NCI pero hiciera una búsqueda de marcadores para recuperar una columna del CI? Debajo NOLOCK, estoy seguro de que sería posible diseñar una situación en la que las columnas del NCI fueran de una versión de la fila pero el CI de una versión diferente. Además, los datos fuera de fila y las páginas lob no estarían protegidos por el pestillo en la página de datos.
Martin Smith
1
@ Martin: De acuerdo, he visto una auto-unión nolocksin encontrar su fila original. Sin embargo, una sola lectura de un campo o fila debe ser coherente.
Andomar
1
@Andomar, a menos que las columnas de la fila abarquen varias páginas. Mira mi enlace.
2
Esto realmente debería ser CW porque la respuesta original no estaba ni cerca de la correcta, Michael proporcionó la esencia de la respuesta actual. Su comentario en contra de la pregunta aún no está de acuerdo con la respuesta editada.