Beim Ausführen einer SELECT-Anweisung mit einem JOIN von zwei Tabellen scheint SQL Server beide Tabellen der Anweisung einzeln zu sperren. Zum Beispiel durch eine Abfrage wie dieses:Deadlock durch SELECT JOIN-Anweisung mit SQL Server
SELECT ...
FROM
table1
LEFT JOIN table2
ON table1.id = table2.id
WHERE ...
fand ich heraus, dass die Reihenfolge der Schlösser an der WHERE-Bedingung abhängt. Der Abfrageoptimierer versucht, einen Ausführungsplan zu erstellen, der nur so viele Zeilen wie erforderlich liest. Wenn also die WHERE-Bedingung eine Spalte von table1 enthält, erhält sie zuerst die Ergebniszeilen aus table1 und dann die entsprechenden Zeilen aus table2. Wenn die Spalte aus Tabelle 2 ist, wird es die andere Weise tun Runde. Komplexere Bedingungen oder die Verwendung von Indizes können sich auch auf die Entscheidung des Abfrageoptimierers auf auswirken.
Wenn die durch eine Erklärung gelesenen Daten anzumerken, dass die Reihenfolge die Reihenfolge entspricht der UPDATE Aussagen garantieren nicht später in der Transaktion mit UPDATE-Anweisungen aktualisiert werden, um die Daten zu lesen von den zwei Tabellen verwendet wurde. Wenn eine andere Transaktion versucht, Daten zu lesen, während eine Transaktion die Tabellen aktualisiert, kann es einen Deadlock verursachen, wenn die SELECT-Anweisung in zwischen den UPDATE-Anweisungen ausgeführt wird, da weder SELECT die Sperre auf der ersten Tabelle noch das UPDATE erhalten kann Holen Sie das Schloss auf den zweiten Tisch. Für Beispiel:
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 = ?
Beide Tabellen stellen eine Art Hierarchie und werden immer zusammen geladen. So macht es Sinn, ein Objekt mit einem SELECT mit einem JOIN zu laden. Das Laden beider Tabellen einzeln würde dem Abfrageoptimierer keine Chance geben, den besten Ausführungsplan zu finden. Da UPDATE-Anweisungen jedoch nur eine Tabelle unter aktualisieren können, kann dies zu Deadlocks führen, wenn ein Objekt geladen wird, während das Objekt von einer anderen Transaktion aktualisiert wird. Aktualisierungen von Objekten führen häufig zu UPDATEs in den beiden Tabellen , wenn Eigenschaften des Objekts aktualisiert werden, die zu verschiedenen Typen der Typhierarchie gehören.
Ich habe versucht, der SELECT-Anweisung Sperrhinweise hinzuzufügen, aber das ändert das Problem nicht . Es verursacht nur den Deadlock in den SELECT-Anweisungen, wenn beide Anweisungen versuchen, die Tabellen zu sperren, und eine SELECT-Anweisung die Sperre in der umgekehrten Reihenfolge der anderen Anweisung erhält. Vielleicht wäre es möglich, Daten für Updates immer mit der gleichen Anweisung zu laden, um die Sperren zu zwingen, in der gleichen Reihenfolge zu sein. Das würde einen Deadlock zwischen zwei Transaktionen verhindern, die die Daten aktualisieren möchten, aber würde nicht verhindern, dass eine Transaktion, die Daten nur liest Deadlock, die andere WHERE-Bedingungen haben muss.
Das einzige Work-a-Round so scheint dies bisher zu sein, dass liest möglicherweise Schlösser überhaupt nicht bekommen. Mit SQL Server 2005 kann dies mithilfe von SNAPSHOT ISOLATION erfolgen. Die einzige Möglichkeit für SQL Server 2000 wäre, die READ UNCOMMITED-Isolationsebene zu verwenden.
Ich würde gerne wissen, ob es eine andere Möglichkeit gibt zu verhindern, dass der SQL Server diese Deadlocks verursacht?
Snapshot-Isolationsstufe? –
Wenn das eine Frage ist, ist die Antwort nein. Es passiert mit allen Isolationsstufen, außer vielleicht READ UNCOMMITTED, das ich nicht getestet habe, weil ich nicht möchte, dass Transaktionen halbaktuelle Daten lesen können. – Reboot