Il suggerimento Tablock innesca deadlock


10

Stavo inserendo due set di dati, utilizzando la registrazione minima, in una tabella heap vuota utilizzando due attività Esegui SQL in esecuzione in parallelo e con SQL del seguente modulo.

INSERT INTO Table (TABLOCK) SELECT FROM ...

Dopo che il processo si è bloccato un po ', una delle attività SQL è diventata una vittima del deadlock. Di seguito è riportato l'output XML del grafico deadlock.

Qualcuno può spiegare cosa stava succedendo sotto il cofano?

  <resource-list>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process9609dc8" mode="Sch-S"/>
     <owner id="process9609dc8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5e13048" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process5e13048" mode="Sch-S"/>
     <owner id="process5e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9609dc8" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
  </resource-list>

Le cose diventano molto più complicate perché ho scoperto che nella maggior parte dei casi le due attività Esegui SQL possono essere eseguite in parallelo con successo. Prova di seguito:

Create table dbo.TablockInsert (c1 int, c2 int, c3 int)

--then issue the script in two Execute Sql Task in parallel you won't fail:
insert into dbo.TablockInsert(TABLOCK) SELECT 1, 1, 1

Poiché l'unica differenza è l'istruzione SELECT ... FROM ..., sembra che l'istruzione SELECT ... FROM ... possa avere un impatto sulla modalità di blocco qui?


È possibile specificare TABLOCKX anziché TABLOCK per impedire il deadlock. Anche se ciò serializzerebbe anche l'accesso alla tabella, otterresti comunque una registrazione minima.
Dan Guzman,

Risposte:


8

La Guida alle prestazioni di caricamento dei dati è stata scritta per SQL Server 2008 ma, per quanto ne so, Microsoft non ha apportato miglioramenti in questo settore per molti anni. Ecco un preventivo per il tuo scenario di caricamento:

Caricamento in blocco di una tabella vuota, non partizionata

Il caricamento dei dati in una tabella non partizionata, mentre un'operazione semplice, può essere ottimizzato in diversi modi.

...

Più operazioni di inserimento simultanee per heap sono possibili solo quando il metodo di massa scelto sceglie i blocchi di aggiornamento di massa (BU) sulla tabella. Sono compatibili due blocchi di aggiornamento in blocco (BU) e quindi due operazioni in blocco possono essere eseguite contemporaneamente.

In questo scenario, sia INSERT ... SELECT che SELECT INTO hanno uno svantaggio. Entrambe queste operazioni accettano un blocco esclusivo (X) a livello di tabella sulla destinazione. Ciò significa che è possibile eseguire una sola operazione di caricamento di massa alla volta, limitando la scalabilità. Tuttavia, BCP, BULK INSERT e Integration Services sono tutti in grado di eseguire blocchi di aggiornamento in blocco (BU), se si specifica il suggerimento TABLOCK.

La parte importante è che non si ottiene un blocco BU con INSERT ... SELECT. Avrai sempre un lucchetto esclusivo sul tavolo, quindi solo uno INSERTpuò essere eseguito alla volta.

Nei commenti hai detto che inserirai 100k righe o meno e che altri processi non verranno eseguiti sulle tabelle durante gli inserimenti. Quando si inviano due query INSERT al database, mi aspetto che accada una delle tre cose seguenti:

  1. Un inserto viene eseguito per primo e blocca l'altro inserto. Il secondo inserto attende fino al completamento del primo inserto.
  2. Un inserto termina prima dell'inizio del secondo inserto. Non esiste un blocco esplicito ma non vengono eseguiti contemporaneamente.
  3. Si ottiene un deadlock e solo un inserto viene completato correttamente.

In tutti i casi, puoi trarre vantaggio o meno dall'aggiunta di un TABLOCKXsuggerimento alla query, quindi questa è la mia raccomandazione di aggirare il deadlock. Se vuoi sapere perché a volte si verifica lo stallo, dovrai cercare un'altra risposta.

In uno scenario diverso in cui è davvero necessario un inserimento parallelo, due modi per aggirare il problema della BU sono partizionare l'heap e far inserire ciascuna sessione in una partizione separata o caricare i dati tramite BCP, BULK INSERT o Integration Services .


Grazie per la risposta, ma la situazione in cui ho riscontrato deadlock è l'unico caso che ho ormai. Nella maggior parte dei casi, quando si inserisce INSERT INTO WITH (TABLOCK) SELECT FROM in parallelo, il lavoro non avrà esito negativo. A proposito, sto usando SQL SERVER 2008 R2. Ho aggiunto un esempio di successo nella mia domanda.
SqlWhale

@tec nei casi in cui non fallisce presumibilmente finiscono per funzionare in serie. Forse hai riscontrato il problema solo quando c'è un certo tempo di avvio, ad esempio per la compilazione del piano.
Martin Smith,

@MartinSmith La query in cui ho riscontrato il problema sul progetto è molto più complessa dell'esempio di SELECT 1, che richiede un sovraccarico di compilazione ma è solo una lettura da un paio di tabelle. Sto cercando di riprodurre questo tipo di deadlock con query più complesse.
SqlWhale

@TecKnowNothing Informazioni su quante righe inserisci? Quante volte al giorno viene eseguito il processo? Altre query SELEZIONANO dalla tabella mentre i dati sono caricati?
Joe Obbish,

@JoeObbish 1. Non credo che il numero di righe sia un problema qui, ne abbiamo solo 4000 - 70000 per ciascuna query e sono dati altamente aggregati per l'uso del cubo. 2. È ancora in fase di test, dovrebbe essere eseguito una volta al giorno. 3. Nessun altro sta leggendo dalla tabella di destinazione.
SqlWhale

4

Si inserisce in dbo.TargetTableda due sessioni e entrambi utilizzando TABLOCKhint.Both process9609dc8e process5e13048processo di holding Sch-Se IXserrature che sono compatibili con l'altro in modo che entrambi processo può contenere contemporaneamente. Ma entrambi vogliono convertire il IXblocco in Exclusive Xtipo. Xle serrature non sono compatibili tra loro. Pertanto, il server SQL ha scelto una delle sessioni come vittima del deadlock invece di aspettarsi all'infinito.

Informazioni di base sul deadlock.

Grafico di compatibilità blocco (Motore di database).

Rilevamento e fine dei deadlock.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.