Lors de l'exécution d'une instruction SELECT avec JOIN de deux tables, SQL Server semble verrouiller individuellement les deux tables de l'instruction. Par exemple par une requête comme ceci:Blocage provoqué par l'instruction SELECT JOIN avec SQL Server
SELECT ...
FROM
table1
LEFT JOIN table2
ON table1.id = table2.id
WHERE ...
J'ai découvert que l'ordre des serrures dépend de la condition WHERE. L'optimiseur de requête essaie de produire un plan d'exécution qui lit uniquement autant de lignes que nécessaire. Donc, si la condition WHERE contient une colonne de table1 , elle obtiendra d'abord les lignes de résultat de table1 et obtiendra ensuite les lignes correspondantes à partir de table2. Si la colonne provient de table2, elle le fera dans l'autre sens round. Conditions plus complexes ou l'utilisation d'index peuvent avoir un effet sur la décision de l'optimiseur de requête aussi.
Lorsque les données lues par une déclaration devrait être mis à jour plus tard dans la transaction avec UPDATE il est pas garanti que l'ordre des instructions UPDATE correspond à l'ordre qui a été utilisé pour lire les données des 2 tables. Si une autre transaction tente de lire des données alors qu'une transaction met à jour les tables , cela peut provoquer un blocage lorsque l'instruction SELECT est exécutée en entre les instructions UPDATE car ni le SELECT ne peut obtenir le verrou la première table, ni la mise à jour prenez le verrou sur la deuxième table. Pour exemple:
T1: SELECT ... FROM ... JOIN ...
T1: UPDATE table1 SET ... WHERE id = ?
T2: SELECT ... FROM ... JOIN ... (locks table2, then blocked by lock on table1)
T1: UPDATE table2 SET ... WHERE id = ?
Les deux tableaux représentent une hiérarchie de type et sont toujours chargés ensemble. Donc il est logique de charger un objet en utilisant un SELECT avec un JOIN. Le chargement des deux tables individuellement ne donnerait pas à l'optimiseur de requête une chance de trouver le meilleur plan d'exécution . Mais puisque les instructions UPDATE ne peuvent mettre à jour qu'une seule table à une heure , cela peut provoquer des blocages lorsqu'un objet est chargé alors que l'objet est mis à jour par une autre transaction. Les mises à jour d'objets provoquent souvent UPDATE sur les deux tables lorsque les propriétés de l'objet qui appartiennent à différents types de la hiérarchie de type sont mises à jour.
J'ai essayé d'ajouter des indicateurs de verrouillage à l'instruction SELECT, mais cela ne change pas le problème. Il provoque simplement le blocage dans les instructions SELECT lorsque les deux instructions tentent de verrouiller les tables et une instruction SELECT obtient le verrou dans l'ordre inverse de l'autre instruction. Peut-être qu'il serait possible de charger les données pour les mises à jour toujours avec la même instruction forçant les serrures à dans le même ordre. Cela empêcherait un blocage entre deux transactions qui veulent mettre à jour les données, mais n'empêcherait pas une transaction qui lit uniquement les données dans un interblocage qui doit avoir des conditions WHERE différentes.
Le seul work-a-round donc cela semble être que les lectures peuvent ne pas avoir de verrous du tout. Avec SQL Server 2005, cela peut être fait en utilisant SNAPSHOT ISOLATION. Le seul moyen pour SQL Server 2000 serait d'utiliser le niveau d'isolement READ UNCOMMITED .
Je voudrais savoir s'il existe une autre possibilité pour empêcher le SQL Server de causer ces interblocages?
niveau d'isolement de capture instantanée? –
Si c'est une question, la réponse est non. Cela se produit avec tous les niveaux d'isolation, sauf peut-être LIRE NON CONVENU que je n'ai pas testé, car je ne veux pas que les transactions puissent lire les données à moitié mises à jour. – Reboot