Domanda

Tutta la documentazione sui deadlock di SQL Server parla dello scenario in cui l'operazione 1 blocca la risorsa A, quindi tenta di accedere alla risorsa B e l'operazione 2 blocca la risorsa B e tenta di accedere alla risorsa A.

Tuttavia, spesso vedo deadlock tra una selezione e un aggiornamento o anche tra più selezioni in alcune delle nostre applicazioni occupate. Trovo che alcuni dei punti più fini dell'output della traccia deadlock siano piuttosto impenetrabili, ma vorrei davvero capire cosa può causare un deadlock tra due singole operazioni. Sicuramente se una selezione ha un blocco di lettura, l'aggiornamento dovrebbe semplicemente attendere prima di ottenere un blocco esclusivo e viceversa?

Questo sta accadendo su SQL Server 2005, non penso che questo faccia la differenza.

È stato utile?

Soluzione

Una volta ho inserito tra i preferiti un buon articolo su Advanced SQL Server lock su SQL-Server-Performance.com. Quell'articolo va oltre la classica situazione di deadlock che hai citato e potrebbe darti un'idea del tuo problema.

Altri suggerimenti

Questo può accadere perché una selezione ha un blocco su due diversi indici, nel frattempo un aggiornamento prende un blocco sugli stessi indici nell'ordine opposto. La selezione ha bisogno di due indici perché il primo indice non copre tutte le colonne a cui deve accedere; l'aggiornamento richiede due indici perché se si aggiorna la colonna chiave di un indice è necessario bloccarlo.

http://blogs.msdn.com/bartd/ archive / 2006/09/25 / 770928.aspx ha una spiegazione fantastica. Le correzioni suggerite includono l'aggiunta di un indice che copre tutte le colonne necessarie per la selezione, il passaggio all'isolamento dello snapshot o la forzatura esplicita della selezione per ottenere un blocco di aggiornamento che normalmente non sarebbe necessario.

Sono sorpreso che nessuno abbia menzionato il suggerimento di blocco WITH (UPDLOCK). È molto utile se si hanno deadlock che coinvolgono ad es. due coppie select-insert in esecuzione in parallelo.

In SQL Server, se si immettono le selezioni con <=>, la seconda selezione attenderà fino al termine della prima selezione. Altrimenti ottengono blocchi condivisi e quando contemporaneamente tentano di passare a blocchi esclusivi, si bloccano.

I blocchi tra singole query possono verificarsi quando bloccano singole righe, non l'intera tabella:

La query di aggiornamento ottiene un blocco di aggiornamento su alcune righe di una tabella e la query di selezione ottiene un blocco di lettura su alcune altre righe della tabella. La query di aggiornamento tenta quindi di ottenere un blocco di aggiornamento sulle righe che vengono lette bloccate e la query di selezione tenta di ottenere un blocco di lettura sulle righe che sono bloccate dall'aggiornamento.

Può diventare ancora più complicato con i blocchi di escalading, ovvero il database decide che ci sono troppe singole righe bloccate da una transazione in modo che debba essere intensificato per bloccare una sezione della tabella o l'intera tabella. Ciò significa che il blocco può influire sulle righe che non sono direttamente coinvolte nella query.

La mia ipotesi è che l'istruzione select acquisisca un blocco di lettura, quando si arriva con l'istruzione update, quindi deve passare a un blocco di scrittura.

L'aggiornamento a un blocco di scrittura richiede la rimozione di tutti gli altri blocchi di lettura (le transazioni di selezione completate). Ma se un altro processo ha già la brillante idea di passare a un blocco in scrittura, allora improvvisamente hai due processi in attesa di rilasciare il blocco in lettura, in modo che possano ottenere il blocco in scrittura.

Se si utilizza select-for-update (UPDLOCK), acquisirà un blocco in scrittura dall'inizio e quindi non si avrà il problema di deadlock.

Leggi correttamente su transazioni e livelli di isolamento: per un lavoro un po 'denso ma abbastanza accurato e neutrale dal punto di vista tecnologico, vedi Principi di elaborazione delle transazioni . Ha scosso il mio mondo (e mi ha dato un bel po 'di mal di testa!).

Non sono sicuro di cosa stai riscontrando problemi o di quale livello di isolamento stai usando. Ma considera questo: per quanto il motore di database sappia, se fai delle letture in una transazione, come può sapere se in seguito scriverai o meno? Livelli di isolamento elevati richiedono il blocco ogni volta che viene eseguita una lettura, possibilmente sull'intera tabella per proteggere dalle letture fantasma, poiché i dati potrebbero influire su una scrittura in un secondo momento.

Desideri che il database attenda arbitrariamente a lungo un blocco esclusivo dei dati? Dai un'occhiata ai tuoi livelli di isolamento e se stai eseguendo inutilmente una serie di letture come una transazione isolata. Tuttavia, non è sempre facile determinare quanto possano essere tollerate le letture sporche.

Dovresti leggere sull'isolamento della transazione: http://msdn.microsoft.com/en-us/library/ms173763. aspx

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top