Les SELECT ne peuvent pas se bloquer avec d'autres SELECT, car ils n'acquièrent que des verrous partagés. Vous dites que nous devrions considérer que ces SELECT "nécessitent désormais des verrous de lecture exclusifs", mais cela ne nous est pas possible car 1) il n'existe pas de exlusive read lock
et 2) les lectures n'acquièrent pas de verrous exclusifs.
Mais vous posez une question plus générale, à savoir si de simples déclarations peuvent aboutir à une impasse. La réponse est un OUI clair et retentissant . Les verrous sont acquis à l'exécution, non analysés en amont et triés puis acquis dans un certain ordre. Il serait impossible pour le moteur de connaître à l'avance les verrous nécessaires, car ils dépendent des données réelles sur le disque, et de lire les données dont le moteur a besoin pour... verrouiller les données.
Les blocages entre des instructions simples (SELECT vs. UPDATE ou SELECT vs. DELETE) en raison d'un ordre d'accès à l'index différent sont assez courants et très faciles à étudier, diagnostiquer et corriger. Mais notez qu'il y a toujours une opération d'écriture impliquée, car les lectures ne peuvent pas se bloquer. Pour cette discussion, l'ajout d'un indicateur UPDLOCK ou XLOCK à un SELECT doit être considéré comme une écriture. Vous n'avez même pas besoin d'un JOIN, un index secondaire peut très bien introduire le problème d'ordre d'accès conduisant à un blocage, voir Interruption de lecture/écriture .
Et enfin, écrire SELECT FROM A JOIN B
ou en écrivant SELECT FROM B JOIN A
est complètement hors de propos. L'optimiseur de requête est libre de réorganiser l'ordre d'accès comme il l'entend, le texte réel de la requête n'impose en aucun cas l'ordre d'exécution.
Mise à jour
J'ai bien peur qu'il n'y ait pas de recette à l'emporte-pièce. La solution dépendra de cas en cas. En fin de compte, dans les applications de base de données, les blocages sont une réalité. Je comprends que cela puisse sembler absurde, comme dans "nous avons atterri sur la Lune mais nous ne pouvons pas écrire une application de base de données correcte", mais il y a des facteurs importants en jeu qui garantissent à peu près que les applications finiront par rencontrer des blocages. Les impasses chanceuses sont les plus facile de traiter les erreurs, il suffit de relire l'état, d'appliquer la logique, de réécrire le nouvel état. Cela étant dit, il existe quelques bonnes pratiques qui peuvent réduire considérablement la fréquence des blocages, jusqu'au point où ils ont pratiquement disparu :
- Essayez d'avoir un modèle d'accès cohérent pour les écritures . Ayez des règles clairement définies indiquant des choses telles que "une transaction doit toujours être classée dans cet ordre :
Customers
->OrderHeaders
->OrderLines
.' Notez que l'ordre doit être obéi dans une transaction . Fondamentalement, classez tous tables dans votre schéma et spécifiez que toutes les mises à jour doivent se produire dans l'ordre de classement. Cela se résume finalement à la discipline de code du contributeur individuel qui écrit le code, car il doit s'assurer qu'il écrit est mis à jour dans le bon ordre à l'intérieur d'une transaction. - Réduire la durée d'écrits. La sagesse habituelle est la suivante :au début de la transaction, effectuez toutes les lectures (lisez l'état existant), puis traitez la logique et calculez de nouvelles valeurs, puis écrivez toutes les mises à jour à la fin de la transaction. Évitez un modèle comme 'lecture->écriture->logique->lecture->écriture', faites plutôt 'lecture->lecture->logique->écriture->écriture'. Bien sûr, le véritable savoir-faire consiste à savoir comment traiter des cas réels, réels et individuels alors qu'apparemment on doit avoir à faire écrit mi-transaction. Une remarque spéciale doit être faite ici à propos d'un type spécifique de transaction :celles pilotées par une file d'attente, qui, par définition même, commencent leur activité en sortant (=une écriture) de la file d'attente. Ces applications ont toujours été notoirement difficiles à écrire et sujettes à des erreurs (en particulier des blocages), heureusement il existe des moyens de le faire, voir Utiliser des tables comme files d'attente .
- Réduire le nombre de lectures. Les scans de table sont le cause la plus fréquente de blocages. Une indexation appropriée éliminera non seulement les blocages, mais pourra également améliorer les performances du processus.
- Isolation d'instantané . C'est ce qui se rapproche le plus d'un déjeuner gratuit pour éviter les impasses. Je l'ai volontairement mis en dernier, car il peut masquer d'autres problèmes (comme une mauvaise indexation) au lieu de les résoudre.
Essayer de résoudre ce problème avec un LockCustomerByXXX
approche j'ai peur ne fonctionne pas. Le verrouillage pessimiste ne s'adapte pas. Concurrence optimiste
les mises à jour sont les chemin à parcourir si vous voulez avoir une sorte de performance décente.