J'ai deux requêtes longues qui sont à la fois sur les transactions et accèdent à la même table mais des lignes complètement séparées dans ces tables. Ces requêtes effectuent également des mises à jour et des insertions basées sur ces requêtes.
Il semble que lorsque ceux-ci s'exécutent simultanément, ils rencontrent un verrou quelconque et cela empêche la tâche de se terminer et se verrouille lors de la mise à jour de l'une des lignes. J'utilise un verrou de ligne exclusif sur les lignes en cours de lecture et le verrou qui s'affiche sur le processus est un verrou lck_m_ix.
Deux questions:
Généralement non, mais cela dépend (réponse la plus souvent utilisée pour SQL Server!)
SQL Server devra verrouiller les données impliquées dans une transaction d'une manière ou d'une autre. Il doit verrouiller les données de la table elle-même et les données des index affectés pendant que vous effectuez une modification. Afin d'améliorer la simultanéité, il existe plusieurs "granularités" de verrouillage que le serveur pourrait décider d'utiliser, afin de permettre l'exécution de plusieurs processus: les verrous de ligne, les verrous de page et les verrous de table sont communs (il y en a plus). L'échelle de verrouillage en jeu dépend de la façon dont le serveur décide d'exécuter une mise à jour donnée. Pour compliquer les choses, il existe également des classifications de verrous comme partagé, exclusif et intentionnel exclusif, qui contrôlent si l'objet verrouillé peut être lu et/ou modifié.
D'après mon expérience, SQL Server utilise principalement des verrous de page pour les modifications apportées à de petites portions de tables, et au-delà d'un certain seuil se transforme automatiquement en verrou de table, si une plus grande partie d'une table semble (d'après les statistiques) être affectée par une mise à jour ou supprimer. L'idée est qu'il est plus rapide de verrouiller une table (un verrou) que d'obtenir et de gérer des milliers de verrous de ligne ou de page individuels pour une grosse mise à jour.
Pour voir ce qui se passe dans votre cas spécifique, vous devez examiner la logique de requête et, pendant l'exécution de vos données, examiner les conditions de verrouillage/blocage dans sys.dm_tran_locks, sys.dm_os_waiting_tasks ou d'autres DMV. Vous voudriez découvrir ce qui se bloque exactement à quelle étape de chacun de vos processus, découvrir pourquoi l'un bloque l'autre.
La version courte:
La version longue:
LCK_M_IX est un verrou intentionnel, ce qui signifie que l'opération placera un verrou X sur un élément subordonné. Par exemple. Lors de la mise à jour d'une ligne dans une table, la table d'opération prend un verrou IX sur la table avant de verrouiller X la ligne en cours de mise à jour/insérée/supprimée. Les verrous d'intention sont une stratégie courante pour gérer les hiérarchies, comme les tables/pages/lignes, car le gestionnaire de verrous ne peut pas comprendre la structure physique des ressources à verrouiller (c'est-à-dire qu'il ne peut pas savoir qu'un verrou X sur la page P1 est incompatible avec un Verrou S sur la ligne R1 car R1 est contenu dans P1). Pour plus de détails, voir Lock Modes .
Le fait que vous voyez des conflits sur les verrous intentionnels signifie que vous essayez d'obtenir des verrous d'objet de haut niveau, comme les verrous de table. Vous devrez analyser votre code source pour la demande bloquée (celle qui demande le verrouillage incompatible avec LCK_M_IX) et supprimer la cause de la demande de verrouillage au niveau de l'objet. Ce que cela signifie dépendra de votre code source, je ne peux pas savoir ce que vous faites là-bas. Je suppose que vous utilisez un indice de verrouillage erroné.
Une approche plus générale consiste à s'appuyer sur SNAPSHOT ISOLATION . Mais cela ne résoudra probablement pas le problème que vous rencontrez, car l'isolement des instantanés ne peut que bénéficier aux problèmes de contention au niveau des lignes, pas aux applications qui demandent des verrous de table.
Un objectif fréquent de l'utilisation des transactions: les garder aussi courtes et douces que possible. J'ai compris dans votre formulation de la question que vous ouvrez une transaction, puis faites toutes sortes de choses, dont certaines prennent beaucoup de temps. Attendre ensuite que plusieurs utilisateurs puissent exécuter ce même code simultanément. Malheureusement, si vous effectuez une insertion au début de cet ensemble de code, puis faites 40 autres choses avant de valider ou d'annuler, il est possible que cette insertion empêche tout le monde d'exécuter le même type d'insertion, tournant essentiellement votre opération de gratuit pour tous en série.
Découvrez ce que fait chaque requête et si vous obtenez des escalades de verrous auxquelles vous ne vous attendez pas. Ce n'est pas parce que vous dites AVEC (ROWLOCK) sur une requête que SQL Server sera en mesure de se conformer ... si vous touchez plusieurs index, des vues indexées, des colonnes calculées persistantes, etc., il y a toutes sortes de raisons pour lesquelles votre verrou de ligne ne peut contenir aucune eau. Vous pouvez également avoir des choses plus tard dans la transaction qui prennent plus de temps que vous ne le pensez, et peut-être que vous ne réalisez pas que les verrous sur tous les objets impliqués dans la transaction (pas seulement l'instruction qui est en cours d'exécution) peuvent être conservés la durée de la transaction.
Différentes bases de données ont des mécanismes de verrouillage différents, mais celles comme SQL Server et Oracle ont différents types de verrouillage.
La valeur par défaut sur SQL Server semble être le verrouillage de page pessimiste - donc si vous avez un petit nombre d'enregistrements, alors tous peuvent être verrouillés.
La plupart des bases de données ne doivent pas se verrouiller lors de l'exécution d'un script, je me demande donc si vous exécutez potentiellement plusieurs requêtes simultanément sans transactions.