Pour travailler à la fois avec Oracle et SQL Server, je suis tout à fait d'accord en ce qui concerne le fait que SQL Server ne sais pas fournir "l'ancienne version" de la ligne durant sa modification dans une transaction depuis une transaction tièrce.
C'est absolument vrai, et à moins de faire des bidouilles de contournement à la main, il n'y a aucun moyen de passer outre.
Moi, tout ce que je dis, c'est que pour les lock, ils se font à la ligne.
Et si c'est effectivement des "pages" ou "blocks", alors SQL Server se débrouille pour ne mettre dedans que les lignes modifiées par la transaction, les autres restent parfaitement disponibles contrairement à ce que tu dis.
Voici un exemple simple, avec une base crée avec les options par défaut, et comme tu peux voir, aucun hint demandant à passer outre le fonctionnement par défaut :
Code :
CREATE TABLE personne ( id int NOT NULL PRIMARY KEY, label varchar(50) NOT NULL ); INSERT INTO personne (id, label) VALUES (1, 'MagicBuzz'); INSERT INTO personne (id, label) VALUES (2, 'leguru2007');
|
Session 1 :
Code :
begin tran UPDATE personne SET label = 'grmpf' WHERE id = 1
|
Session 2
Code :
begin tran UPDATE personne SET label = 'plop' WHERE id = 2
|
Il ne se produit aucun lock.
Par contre, si depuis la session 2 je tente de toucher (lecture ou écriture) la ligne id=1 sans hint, alors jesuis locké, et inversement depuis la session 1 sur la ligne id=2.
Donc page, block ou ce que tu veux, seules les lignes impactées par la transaction sont verrouillées.
En revanche, la transaction est aveugle.
En effet, en repartant des données initiale :
Session 1 :
Code :
begin tran UPDATE personne SET label = 'plop' WHERE label = 'leguru2007'
|
Session 2 :
Code :
begin tran UPDATE personne SET label = 'cuicui' WHERE label = 'leguru2007'
|
=> Locké, logique, on ne sais pas si "leguru2007" existera toujours à la fin de la transaction de la session 1
Session 3 :
Code :
begin tran UPDATE personne SET label = 'grmpf' WHERE label = 'plop'
|
=> Locké, logique, on ne sais pas si "plop" existera à la fin de la transaction de la session 1
Session 4 :
Code :
begin tran UPDATE personne SET label = 'nerd' WHERE label = 'Harko'
|
=> Locké, pas logique, puisqu'on sait que quels que soient les résultats des transactions 1, 2 et 3, le label "Harko" n'existera jamais. Il y a un lock ici non pas de la table ou de la page, mais simplement de la valeur en cours de modification. Etant incapable de savoir quelle sera la valeur finale ni quelle était la valeur initiale, SQL Server est obligé d'attendre que les locks sur toutes les lignes soient relâchés.
C'est là toute la subtilité. Tant que le filtre porte sur des champs qui ne sont pas modifiés par une transaction, les locks n'entrent pas en collision tant qu'on travaille sur des lignes différentes. Par contre, dès qu'on filtre sur un champ en cours de modification, on a l'impression d'avoir un lock sur toute la table, mais ce n'est pas vrai, c'est juste qu'à ce stade, toutes les lignes en cours de modification étaient inconnues, on est incapable d'effectuer le filtre.
J'ai oublié de tester avec une 5° session, voir si la ligne avec id=1 est lockée par la 4° session, mais je ne pense pas.
Message édité par MagicBuzz le 21-12-2007 à 18:59:57