Istruzioni SELECT di SQL Server che causano il blocco
-
06-07-2019 - |
Domanda
Stiamo usando un database SQL Server 2005 (senza controllo delle versioni delle righe) con un'enorme istruzione select e stiamo vedendo che blocca l'esecuzione di altre istruzioni (visto usando sp_who2
). Non pensavo che le istruzioni SELECT potessero causare il blocco - c'è qualcosa che posso fare per mitigare questo?
Soluzione
SELECT può bloccare gli aggiornamenti. Un modello di dati e una query progettati correttamente causano solo un blocco minimo e non rappresentano un problema. Il suggerimento "solito" di NOLOCK è quasi sempre la risposta sbagliata. La risposta corretta è ottimizzare la query in modo che non esegua la scansione di tabelle enormi.
Se la query non è sintonizzabile, è necessario innanzitutto considerare Livello ISOLATION SNAPSHOT , in secondo luogo dovresti considerare l'utilizzo di DATABASE SNAPSHOTS e l'ultima opzione dovrebbe essere DIRTY LEGGI (ed è meglio cambiare il livello di isolamento piuttosto che usare NOLOCK SUGGERIMENTO). Si noti che le letture sporche, come indica chiaramente il nome, restituiranno dati incoerenti (ad esempio, il foglio totale potrebbe essere sbilanciato).
Altri suggerimenti
Da documentazione :
I blocchi??
Shared (S)
consentono alle transazioni simultanee di leggere(SELECT)
una risorsa sotto il controllo pessimistico della concorrenza. Per ulteriori informazioni, vedereTipi di controllo della concorrenza
. Nessun'altra transazione può modificare i dati mentre esistono blocchicondivisi (S)
sulla risorsa. I blocchicondivisi (S)
su una risorsa vengono rilasciati al termine dell'operazione di lettura, a meno che il livello di isolamento della transazione non sia impostato su lettura ripetibile o superiore o venga utilizzato un suggerimento di blocco per conservareblocchi condivisi (S)
per la durata della transazione.
Un blocco condiviso
è compatibile con un altro blocco condiviso o un blocco di aggiornamento, ma non con un blocco esclusivo.
Ciò significa che le tue query SELECT
bloccheranno le query UPDATE
e INSERT
e viceversa.
Una query SELECT
inserirà un blocco condiviso temporaneo quando legge un blocco di valori dalla tabella e lo rimuoverà al termine della lettura.
Per il momento in cui esiste il blocco, non sarai in grado di fare nulla con i dati nell'area bloccata.
Due query SELECT
non si bloccheranno mai (a meno che non siano SELEZIONA PER AGGIORNAMENTO
)
È possibile abilitare il livello di isolamento SNAPSHOT
sul database e utilizzarlo, ma si noti che non impedirà il blocco delle query UPDATE
da SELECT
query (che sembra essere il tuo caso).
Tuttavia, impedirà che le query SELECT
vengano bloccate da UPDATE
.
Si noti inoltre che SQL Server
, a differenza di Oracle
, utilizza il gestore dei blocchi e mantiene i blocchi in un elenco collegato in memoria.
Ciò significa che sotto carico pesante, il semplice fatto di posizionare e rimuovere un blocco potrebbe essere lento, poiché l'elenco collegato dovrebbe essere bloccato dal thread di transazione.
Per eseguire letture sporche puoi:
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
//Your code here
}
o
SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."
ricorda che devi scrivere WITH (NOLOCK) dopo ogni tabella che vuoi leggere sporco
È possibile impostare il livello di transazione leggere Non confermato
Potresti anche ottenere deadlock:
"deadlock che coinvolgono solo una tabella" http: // sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx
e o risultati errati:
" Seleziona in READ COMMITTED e REPEATABLE READ potrebbe restituire risultati errati. "
Puoi usare il suggerimento per la tabella WITH (READPAST)
. È diverso da WITH (NOLOCK)
. Riceverà i dati prima dell'avvio della transazione e non bloccherà nessuno. Immagina di aver eseguito la dichiarazione prima dell'inizio della transazione.
SELECT * FROM table1 WITH (READPAST)