Quando si esegue un'istruzione SELECT con un JOIN di due tabelle, SQL Server sembra che blocchi singolarmente entrambe le tabelle dell'istruzione. Ad esempio una query come questo:Deadlock causato dall'istruzione SELECT JOIN con SQL Server
SELECT ...
FROM
table1
LEFT JOIN table2
ON table1.id = table2.id
WHERE ...
ho scoperto che l'ordine dei blocchi dipende dalle condizioni WHERE. L'ottimizzatore di query tenta di produrre un piano di esecuzione che legge solo le righe necessarie. Quindi, se la condizione WHERE contiene una colonna della tabella1 , per prima cosa otterrà le righe dei risultati da table1 e quindi otterrà le corrispondenti righe da table2. Se la colonna proviene da table2 lo farà nell'altro modo round. Condizioni più complesse o l'uso di indici possono avere un effetto su anche la decisione di Query Optimizer.
Quando i dati letti da una dichiarazione devono essere aggiornati successivamente nella transazione con le istruzioni UPDATE non è garantito che l'ordine delle UPDATE dichiarazioni corrisponde l'ordine che è stato utilizzato per leggere i dati dalle tabelle 2. Se un'altra transazione tenta di leggere i dati mentre una transazione sta aggiornando le tabelle , può causare un deadlock quando l'istruzione SELECT viene eseguita in tra le istruzioni UPDATE perché né SELECT può ottenere il blocco su la prima tabella né l'UPDATE ottenere il blocco sul secondo tavolo. Ad esempio, :
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 = ?
Entrambe le tabelle rappresentano una gerarchia di tipo e sono sempre caricati in comune. Quindi è che ha senso caricare un oggetto usando un SELECT con un JOIN. Il caricamento di entrambe le tabelle individualmente non consentirebbe a Query Optimizer di trovare il miglior piano di esecuzione . Ma dal momento che le istruzioni UPDATE possono aggiornare una tabella solo in un'ora , questo può causare deadlock quando viene caricato un oggetto mentre l'oggetto viene aggiornato da un'altra transazione. Gli aggiornamenti degli oggetti spesso causano AGGIORNAMENTI su entrambe le tabelle quando vengono aggiornate le proprietà dell'oggetto che appartengono a tipi diversi della gerarchia di tipi .
Ho provato ad aggiungere suggerimenti di blocco all'istruzione SELECT, ma ciò non risolve il problema con . Causa solo il deadlock nelle istruzioni SELECT quando entrambe le istruzioni tentano di bloccare le tabelle e un'istruzione SELECT ottiene il blocco nell'ordine opposto dell'altra istruzione. Forse sarebbe possibile per caricare i dati per gli aggiornamenti sempre con la stessa istruzione forzando i blocchi a essere nello stesso ordine. Ciò impedirebbe un deadlock tra due transazioni che desidera aggiornare i dati, ma non impedirebbe una transazione che legge solo i dati deadlock che deve avere condizioni WHERE diverse.
L'unica work-a-round quindi sembra che le letture potrebbero non avere lucchetti . Con SQL Server 2005 questo può essere fatto usando SNAPSHOT ISOLATION. L'unico modo per SQL Server 2000 per l' è l'utilizzo del livello di isolamento READ UNCOMMITED .
Mi piacerebbe sapere se esiste un'altra possibilità per impedire a SQL Server di provocare questi deadlock?
livello di isolamento dello snapshot? –
Se questa è una domanda la risposta è no. Succede con tutti i livelli di isolamento, tranne forse LEGGI NON CORRETTO che non ho provato, perché non voglio che le transazioni possano leggere dati semestrali. – Reboot