TABLOCK vs TABLOCKX

Qual è la differenza tra TABLOCK e TABLOCKX http://msdn.microsoft.com/en-us/library/ms187373.aspx afferma che TABLOCK è un blocco condiviso mentre TABLOCKX è un blocco esclusivo. Il primo forse è solo un blocco di indice? E qual è il concetto di condivisione di un lucchetto?

Grande differenza, TABLOCK proverà ad afferrare i blocchi “condivisi” e i TABLOCKX esclusivi di TABLOCKX .

Se sei in una transazione e prendi un blocco esclusivo su un tavolo, EG:

SELECT 1 FROM TABLE WITH (TABLOCKX)

Nessun altro processo sarà in grado di afferrare eventuali blocchi sul tavolo, il che significa che tutte le query che tentano di parlare con il tavolo saranno bloccate fino a quando la transazione non si impegna.

TABLOCK solo un blocco condiviso, i blocchi condivisi vengono rilasciati dopo l’esecuzione di un’istruzione se l’isolamento della transazione è READ COMMITTED (impostazione predefinita). Se il tuo livello di isolamento è più alto , ad esempio: SERIALIZABLE , i blocchi condivisi vengono mantenuti fino alla fine di una transazione.


I blocchi condivisi sono, hmmm, condivisi. Significato 2 transazioni possono entrambi leggere i dati dalla tabella allo stesso tempo se entrambi tengono un blocco S o IS sul tavolo (tramite TABLOCK ). Tuttavia, se la transaction A contiene un blocco condiviso su una tabella, la transaction B non sarà in grado di accedere a un blocco esclusivo fino a quando tutti i blocchi condivisi non verranno rilasciati. Leggi quali sono i blocchi compatibili con i quali su msdn .


Entrambi i suggerimenti fanno in modo che il db non esegua più blocchi granulari (come blocchi a livello di riga o di pagina). In linea di principio, i blocchi più granulari consentono una maggiore concorrenza. Ad esempio, una transazione potrebbe aggiornare la riga 100 nella tabella e un’altra riga 1000, allo stesso tempo da due transazioni (diventa complicata con i blocchi di pagina, ma consente di saltarla).

In generale i blocchi granulari sono ciò che si desidera, ma a volte si consiglia di ridurre la concorrenza db per aumentare le prestazioni di una particolare operazione ed eliminare la possibilità di deadlock.

In generale non TABLOCK o TABLOCKX meno che non ne avessi assolutamente bisogno per qualche edge case.

Un vecchio articolo su mssqlcity tenta di spiegare i tipi di blocchi:

I blocchi condivisi vengono utilizzati per operazioni che non modificano o aggiornano i dati, ad esempio un’istruzione SELECT.

I blocchi di aggiornamento vengono utilizzati quando SQL Server intende modificare una pagina e successivamente promuove il blocco della pagina di aggiornamento a un blocco di pagina esclusivo prima di apportare effettivamente le modifiche.

I blocchi esclusivi vengono utilizzati per le operazioni di modifica dei dati, ad esempio UPDATE, INSERT o DELETE.

Ciò che non discute sono Intent (che fondamentalmente è un modificatore per questi tipi di lock). I blocchi Intent (Shared / Exclusive) sono blocchi mantenuti a un livello superiore rispetto al blocco reale. Quindi, ad esempio, se la tua transazione ha un blocco X su una riga, avrà anche un blocco IX a livello di tabella (che impedisce ad altre transazioni di tentare di ottenere un blocco incompatibile a un livello superiore nella tabella (ad esempio uno schema blocco di modifica) fino al completamento o al rollback della transazione).


Il concetto di “condivisione” di un blocco è abbastanza semplice: più transazioni possono avere un blocco condiviso per la stessa risorsa, mentre solo una singola transazione può avere un blocco esclusivo e una serratura esclusiva preclude qualsiasi transazione dall’ottenere o mantenere un blocco condiviso.

Questo è più di un esempio in cui TABLOCK non ha funzionato per me e TABLOCKX ha funzionato.

Ho 2 sessioni, che usano entrambi il livello di isolamento predefinito (READ COMMITTED):

La Sessione 1 è una transazione esplicita che copierà i dati da un server collegato a un insieme di tabelle in un database e impiegherà alcuni secondi per essere eseguita. [Esempio, elimina Domande] Sessione 2 è un’istruzione di inserimento, che inserisce semplicemente le righe in una tabella a cui la Sessione 1 non ha apportato modifiche. [Esempio, inserisce le risposte].

(In pratica ci sono più sessioni che inseriscono più record nella tabella, simultaneamente, mentre la Sessione 1 sta eseguendo la sua transazione).

La Sessione 1 deve interrogare la tabella in cui inserire la Sessione 2 perché non può cancellare i record che dipendono dalle voci che sono state aggiunte dalla Sessione 2. [Esempio: Elimina domande a cui non è stata data una risposta].

Quindi, mentre la Sessione 1 è in esecuzione e la Sessione 2 tenta di inserirla, la Sessione 2 perde ogni volta in un deadlock.

Quindi, un’istruzione delete nella Session 1 potrebbe essere qualcosa del tipo: DELETE tblA FROM tblQ LEFT JOIN tblX su … LEFT JOIN tblA a ON tblQ.Qid = tblA.Qid WHERE … a.QId IS NULL e …

Il deadlock sembra essere causato dalla contesa tra l’interrogazione di tblA mentre Session 2, [3, 4, 5, …, n] tenta di inserire in tblA.

Nel mio caso, potrei cambiare il livello di isolamento della transazione della Sessione 1 per essere SERIALIZZABILE. Quando ho fatto questo: il gestore delle transazioni ha distriggersto il supporto per le transazioni remote / di rete.

Quindi, potrei seguire le istruzioni nella risposta accettata qui per aggirarlo: il gestore delle transazioni ha distriggersto il suo supporto per le transazioni remote / di rete

Ma a) Non ero a mio agio nel cambiare il livello di isolamento in SERIALIZABLE in primo luogo – presumibilmente degrada le prestazioni e potrebbe avere altre conseguenze che non ho considerato, b) non capisco perché farlo improvvisamente abbia causato la transazione un problema con i server collegati e c) non so quali possibili buchi potrei aprire consentendo l’accesso alla rete.

Sembravano esserci solo 6 query all’interno di una transazione molto grande che stanno causando il problema.

Quindi, ho letto su TABLOCK e TabLOCKX.

Non ero chiaro sulle differenze e non sapevo se avrebbe funzionato. Ma sembrava come sarebbe. Per prima cosa ho provato TABLOCK e non sembrava fare alcuna differenza. Le sessioni in competizione hanno generato gli stessi deadlock. Quindi ho provato TABLOCKX e non ho più deadlock.

Quindi, in sei punti, tutto ciò che dovevo fare era aggiungere un WITH (TABLOCKX).

Quindi, un’istruzione delete in Session 1 potrebbe essere qualcosa del tipo: DELETE tblA FROM tblQ q SINISTRA JOIN tblX x on … SINISTRA UNISCITI tblA a WITH (TABLOCKX) ON tblQ.Qid = tblA.Qid WHERE … a.QId È NULL e …