L’utilisation du tag de table NOLOCK, hélas largement prisé par de nombreux développeurs, est, la plupart du temps, une absurdité conduisant à des résultats potentiellement faux. Est-il possible de faire autrement pour minimiser les blocages induit par les verrouillages dans SQL Server ? Réponse OUI !
À la suite de cette remarque :
« …je passe aussi sur le NOLOCK qui est une véritable connerie en production et donne des valeurs fausses ! »
Publiée ici :
Mon interlocuteur me répondais :
« Merci pour cette précision. Comme vous abordez le sujet du NOLOCK effectivement j’ai constaté certaines fois en production on avait des valeurs totalement erronées, mais je n’arrivais pas à me l’expliquer. J’ai maintenant une piste et je vais creuser du côté du NOLOCK que nous utilisons beaucoup en production sur une base de données CRM 2013. Aussi par quoi pouvons nous remplacer le NOLOCK ?? »
Je lui donnais donc l’explication suivante…
Le « NOLOCK » peut parfaitement se remplacer par le niveau d’isolation SNAPSHOT par exemple…
NOLOCK ne signifie pas « je ne pose pas de verrou« , mais plus précisément : « j’ignore qu’il y a des verrous et je lit ce que je peut » (ceci est plus connu dans la littérature professionnelle sous le nom de lecture dans le chaos…). Vous pouvez donc lire plusieurs fois les mêmes données ou encore ne pas lire certaines.
Quid du mode SNAPSHOT ?
SNAPSHOT fait du verrouillage optimiste pour les lectures. Par défaut SQL Server fait du verrouillage pessimiste, c’est à dire que les lectures posent des verrous qui permettent d’autres lectures concurrentes (verrous partagés, mode « SHARE »), mais empêchent les écritures des autres utilisateurs. Conceptuellement, le verrouillage optimiste (donc via le mode d’isolation SNAPSHOT) fait une copie (si besoin) des données avant de permettre leurs lectures. Comme vous travaillez sur une copie, les utilisateurs concurrent peuvent modifier les vraies ligne sans que cela vous concerne. Bien entendu il peut toujours y avoir des conflits, mais cela réduit considérablement le nombre de verrous bloquants tout en gardant l’intégrité et la consistante de la base, ce qui n’est pas du tout le cas du NOLOCK.
Alors, Ã quoi sert le NOLOCK ?
Cela peut servir pour certains cas ou l’on désire des résultats dont on se fout de l’intégrité ou de la précision. Souvent dans le domaine de la statistique.
par exemple si vous voulez savoir combien les français ont d’enfant par foyer et scrutez donc, pour ce faire, une table de 60 millions de lignes (population française), je ne suis pas sûr que dans un camembert représentant la chose, on fasse la distinction des quelques pixels de l’imprécision de la 6e décimale du résultat liées à quelques mauvaises lectures de lignes !
On utilise d’ailleurs très souvent le NOLOCK pour des tâches d’administration systèmes dans SQL Server afin d’éviter tout blocage au risque de perdre quelques lignes, ce qui n’a pas toujours une importance capitale lorsque l’on veut remonter quelques informations concernant les 20% de requêtes les moins performantes !
Mais alors, le SNAPSHOT fait la même chose en mieux ?
Oui et non… Certes il permet de garantir l’intégrité, la consistance, etc… mais son mécanisme est plus lourd (un peu moins rapide) et consomme des ressources pour générer les copies (SNAPSHOT). Rassurez-vous il est assez malin pour ne faire ces copies qui s’il a besoin de les faire… En d’autres termes si aucun utilisateur concurrent veut faire des modif sur le jeu de lignes que vous manipulez en mode SNAPSHOT, aucune copie ne sera générée. Mais si, lorsque vous avez démarré une lecture en mode SNAPSHOT, un utilisateur concurrent veut modifier des lignes, et bien la copie sera réalisée au cours de votre lecture sans que vous vous en aperceviez… En quelque sorte le système fonctionne à l’envers… Bien évidemment il faut un espace de stockage pour ces copies et c’est la base tempdb qui s’y colle. Il faut donc, la dimensionner correctement…
Tiens, Ã nouveau un travail de DBA !
Des conflits ! Quels conflits ?
J’ai précédemment parlé de conflits possible avec l’utilisation du mode SNAPSHOT. En effet, si vous voulez modifier des données lors d’une transaction en mode d’isolation SNAPSHOT, c’est possible, mais ces modifications seront faites sur la copie, et non sur la base originale, et seront reportées sur la base originale au moment du COMMIT. Deux hypothèses se font alors jour :
â– soit aucune ligne visée par vos modifications faites en mode SNAPSHOT n’a été modifié dans une autre session directement sur la base, alors la mise à jour est appliquée.
Ou alors :
â– s’il existe au moins une ligne qui a été modifiée par une autre session entre temps sur la base originale, alors vos modifications ne pourront être appliquées aux données originales et vont êtres abandonnées.
Dans ce dernier cas vous obtiendrez une message d’erreur (3960) assez abscons, qui indique :
« La transaction d’isolement d’instantané a été abandonnée en raison d’un conflit de mise à jour. … »
Notez qu’il existe un autre tag plus intéressant que le NOLOCK…. Le READPAST !… Qui fait presque la même chose, mais ignore tout ce qui est verrouillé !
Les modes d’isolation selon la norme SQL
Sachez que le mode d’isolation SNAPSHOT ne fait pas partie de la norme SQL qui n’autorise que les modes d’isolation suivants :
0 – READ UNCOMMITTED : lecture des données invalides (non « committées »)
1 – READ COMMITTED : lecture de données valides (ce qui n’empêche pas certaines anomalies transactionnelles comme la lecture non répétable, ou l’apparition de lignes fantômes)
2 – REPEATABLE READ : lecture répétable de données (ce qui n’empêche pas certaines anomalies transactionnelles comme l’apparition de lignes fantômes)
3 – SERIALIZABLE : lecture en mode série (aucun accès concurrent aux tables lors des mises à jour, ce qui empêche toute anomalies)
Évidemment plus on monte le niveau d’isolation, plus le verrouillage est important et moins les accès concurrents peuvent travailler.
La norme SQL considère que les manipulation des données doivent porter sur des valeurs « vivantes ». Hors, en utilisant le mode SNAPSHOT et son versionnement des lignes, ont est appelé à lire potentiellement des valeurs antérieurs des données, ce n’est donc pas une lecture de l’état actuel des valeurs dans la base…
Pour informations, des SGBRD comme Oracle, ou PostGreSQL fonctionnent nativement en mode d’isolation SNAPSHOT, autrement dit utilisent systématiquement le verrouillage optimiste et ne savent pas faire autres choses (verrouillage pessimiste en particulier) voir ne savent même pas utiliser certains autres niveau d’isolation. Par exemple PostGreSQL ne permet pas de faires des transaction en mode READ UNCOMMITTED et Oracle ne permettent pas d’utiliser le niveau d’isolation REPEATABLE READ…
Activer le mode s’isolation SNAPSHOT
Pour permettre ce mode d’isolation, vous devez d’abord autoriser la base à utiliser le mode SNAPSHOT. Ce paramétrage est à deux niveaux :
permet d’utiliser à tout moment le mode d’isolation SNAPSHOT qui doit être introduit préalablement par la commande SET TRANSACTION ISOLATION SNAPSHOT ou par un tag de table (SNAPSHOT)
… et :
qui place d’office toutes les lectures en mode SNAPSHOT (comme le fait Oracle ou PostGreSQL);
ATTENTION : pour assurer le versionnement des lignes, SQL Server rajoute à toutes les lignes de toutes les tables une information de version qui est codé sur 14 octets. Ceci peut prendre du temps à mettre en œuvre, en particulier sur de grosses bases.
Appendice :
Pour une démonstration des effets du NOLOCK : http://mssqlserver.fr/les-dangers-du-nolock/
Expert S.G.B.D relationnelles et langage S.Q.L
Moste Valuable Professionnal Microsoft SQL Server
Société SQLspot : modélisation, conseil, formation,
optimisation, audit, tuning, administration SGBDR
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.
L’entreprise SQL Spot
Le site web sur le SQL et les SGBDR