Dans le cadre de la série d'automne des journées de formation aux bases de données de Quest, Brent Ozar, Microsoft Certified Master, a présenté un didacticiel sur "Éviter les blocages avec le réglage des requêtes". Le programme s'est concentré sur les trois problèmes de concurrence qui se produisent dans SQL Server, trois façons de les résoudre et une façon qui semble les résoudre, mais qui ne le fait vraiment pas.
Problèmes de simultanéité :verrouillage, blocage et interblocages dans SQL Server
Quels sont les problèmes de simultanéité ? Ils se produisent lorsque les requêtes tentent d'éviter les conflits les unes avec les autres sur des objets de base de données tels que des tables. Ce sont :
- Verrouillage – Les requêtes le font tout le temps pour empêcher d'autres requêtes d'utiliser une table en même temps. Il s'agit d'une opération de base de données normale.
- Blocage – Cela se produit lorsqu'une requête a un verrou normal, mais qu'une autre requête tente d'acquérir le même verrou. La deuxième requête doit attendre aussi longtemps que nécessaire pour que la première requête libère le verrou. Selon la nature de la première requête, la seconde peut attendre très peu ou très longtemps. Ce sont ces longues attentes qui affectent vraiment les performances.
- Interblocage – Des interblocages se produisent lorsqu'une requête prend un verrou, une autre requête prend un verrou différent, puis chacun veut acquérir le verrou de l'autre. SQL Server résout ce problème en désignant l'une des requêtes comme victime et en la tuant pour rompre l'impasse. Même si l'une des requêtes peut continuer, cela a également un impact sur les performances.
Résoudre les problèmes de simultanéité
Que vous rencontriez des blocages ou des interblocages dans SQL Server, il existe des moyens de résoudre les problèmes de simultanéité. Brent a présenté ces trois méthodes et a passé la majeure partie du reste de la session à se concentrer sur la seconde :corriger le mauvais code.
- Assez d'index pour accélérer vos requêtes, mais pas au point de ralentir les choses en faisant en sorte que les requêtes maintiennent plus de verrous pendant plus longtemps
- Ajustez votre code transactionnel afin que les requêtes passent par les tables dans le même ordre prévisible à chaque fois
- Utilisez le bon niveau d'isolation pour les besoins de votre application
Alors qu'il sautait dans la partie pratique du programme, Brent a commenté l'utilisation des instructions NOLOCK pour le blocage et l'interblocage. Il a averti que NOLOCK ne résout pas vraiment ces problèmes car il s'appuie sur des "lectures sales" - essentiellement, il ignore les verrous de ligne des autres requêtes.
Dans sa démonstration à l'aide de la base de données Stack Overflow, il a créé une requête simple qui recherchait et comptait les personnes nommées "Alex". Ensuite, il a créé une autre requête qui exécuterait une mise à jour sur les personnes qui ne sont pas nommé Alex—pas d'insertions ou de suppressions d'enregistrements. Une requête ne doit avoir rien à voir avec l'autre. Mais, les exécuter ensemble conduit à des résultats différents dans le nombre de personnes nommées Alex. En effet, NOLOCK vous permet de voir les données qui n'ont pas été validées, ce qui conduit à des résultats aléatoires que vous ne pouvez pas prédire. Cela ne se produit qu'en concurrence.
Il est clair qu'un meilleur correctif est nécessaire pour le blocage et l'interblocage dans SQL Server, qui n'entraîne pas de résultats aléatoires et imprévisibles.
Une meilleure solution pour les blocages SQL
Brent a ensuite montré comment résoudre un blocage en modifiant le code qui le provoque. Sa première démo montrait une situation simple impliquant deux tables afin que le public puisse voir une impasse au ralenti pendant qu'elle se produisait. Étant donné que SQL Server recherche les interblocages toutes les 5 secondes et tue la requête la plus facile à annuler, nous avons pu voir la victime de l'interblocage émerger.
Dans une situation simple, le conseil le plus général s'applique, et c'est de toucher les tables dans le même ordre à chaque fois lors de la construction des requêtes. Cela empêchera généralement les requêtes de se bloquer les unes les autres.
Qu'en est-il des requêtes plus complexes ? Pour ce scénario, Brent a utilisé une situation plus réaliste qui pourrait facilement survenir sur Stack Overflow où deux personnes votent pour les questions de l'autre. Étant donné que les mêmes utilisateurs sont impliqués dans les deux transactions, cela provoque un blocage.
Ici, il ne suffit pas de parcourir chaque table dans le même ordre à chaque fois, mais il est également nécessaire de minimiser le nombre de fois que chaque table est touchée. Comme Brent l'a expliqué, le correctif peut impliquer un code laid qui provoque le blocage des requêtes, mais au moins pas un blocage. Dans ce cas, un bloc de courte durée qui permet aux deux requêtes de s'exécuter jusqu'à la fin est préférable à un blocage qui met fin à l'une d'entre elles.
Personne ne veut modifier le code dans des centaines de requêtes, alors concentrez-vous sur celles qui se bloquent constamment, supprimez toutes les lignes inutiles de la transaction et n'ayez pas peur d'introduire un bloc pour éviter un blocage.