Lectures sales de SQL Server 2008 R2 - comment non atomique?

11

Je me demande "comment sale" les lectures sales peuvent passer sous un niveau d'isolement sans engagement. Je comprends que les lignes qui ont été mises à jour mais pas encore validées sont visibles, mais:

  1. Une ligne peut-elle apparaître comme partiellement mise à jour, c'est-à-dire que certaines colonnes sont mises à jour et d'autres non?
  2. Une seule colonne peut-elle apparaître partiellement mise à jour. Par exemple, si vous avez une colonne varchar (4000) qui était en train d'être complètement mise à jour et en supposant qu'elle contient en fait 4000 caractères. Pouvez-vous lire, disons, 2k caractères de l'état précédent et 2k caractères de son nouvel état? Qu'en est-il de varchar (max) avec une longueur> 8k?

Mise à jour: Après quelques débats, le consensus minimal est que si la taille de la colonne est> 8 Ko, des lectures incorrectes, même dans la colonne elle-même, sont possibles.

Michael Goldshteyn
la source

Réponses:

7

MODIFIÉ après avoir lu le lien du forum MSDN du commentaire , très intéressant.

Quel que soit le niveau d'isolement, deux utilisateurs ne peuvent pas mettre à jour une seule page simultanément, ni aucun utilisateur ne peut lire une page partiellement mise à jour. Imaginez simplement comment SQL Server traiterait une page où l'en-tête indique que Col3 commence à l'octet 17. Mais cela commence vraiment à l'octet 25, car cette partie de la ligne n'a pas encore été mise à jour. Il n'y a aucun moyen qu'une base de données puisse gérer cela.

Mais pour les lignes de plus de 8 Ko, plusieurs pages sont utilisées, ce qui rend possible une colonne à moitié mise à jour. Copié à partir du lien MSDN (en cas de rupture du lien), lancez cette requête dans une fenêtre:

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

Cela crée une table, puis la met à jour avec une chaîne de 100 000x le même caractère. Pendant l'exécution de la première requête, lancez cette requête dans une autre fenêtre:

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

La deuxième requête s'arrête lorsqu'elle lit une colonne à moitié mise à jour. Autrement dit, lorsque le premier caractère est différent du dernier. Il se terminera rapidement, prouvant qu'il est possible de lire des colonnes semi-mises à jour. Si vous supprimez l' nolockindice, la deuxième requête ne se terminera jamais.

Résultat surprenant! Une colonne XML à moitié mise à jour peut casser un (nolock)rapport, car le XML serait mal formé.

Andomar
la source
1
Ce n'est apparemment pas toujours vrai, par social.msdn.microsoft.com/Forums/en-US/transactsql/thread/… , mais quels types de colonnes peuvent être vus partiellement mis à jour est encore un peu un mystère.
Les verrous @Andomar AFAIK empêcheraient les lectures d'une page partiellement mise à jour mais que se passerait-il si certaines valeurs de colonne étaient lues à partir d'un NCI mais qu'il effectuait une recherche de signet pour récupérer une colonne du CI. Sous NOLOCKJe suis sûr qu'il serait possible de concevoir une situation où les colonnes NCI provenaient d'une version de la ligne mais le CI d'une version différente. De plus, les données hors ligne et les pages lob ne seraient pas protégées par le verrou de la page de données.
Martin Smith
1
@Martin: D'accord, j'ai vu un individu se joindre à nolockne pas trouver sa ligne d'origine. Cependant, une seule lecture d'un champ ou d'une ligne doit être cohérente.
Andomar
1
@Andomar, sauf si les colonnes de la ligne s'étendent sur plusieurs pages. Voir mon lien.
2
Cela devrait vraiment être CW parce que la réponse originale était loin d'être à droite, Michael a fourni l'essentiel de la réponse actuelle. Votre commentaire contre la question n'est toujours pas d'accord avec la réponse modifiée.