SELEZIONA / INSERISCI Deadlock


10

Questa istanza ospita i database di SharePoint 2007 (SP). Abbiamo riscontrato numerosi deadlock SELECT / INSERT su una tabella fortemente utilizzata nel database del contenuto SP. Ho ristretto le risorse coinvolte, entrambi i processi richiedono blocchi sull'indice non cluster.
INSERT richiede un blocco IX sulla risorsa SELECT e SELECT richiede un blocco S sulla risorsa INSERT. Il grafico del deadlock mostra tre risorse, 1.) due da SELECT (thread parallele produttore / consumatore) e 2.) INSERT.
Ho allegato il grafico del deadlock per la tua recensione. Poiché si tratta di codice Microsoft e strutture di tabelle, non è possibile apportare modifiche.
Tuttavia, sul sito MSFT SP ho letto che raccomandano di impostare l'opzione di configurazione a livello di istanza MAXDOP su 1. Poiché questa istanza è condivisa tra molti altri database / applicazioni, questa impostazione non può essere disabilitata.


Pertanto, ho deciso di provare a impedire che queste istruzioni SELECT diventassero parallele. So che questa non è una soluzione ma più una modifica temporanea per aiutare con la risoluzione dei problemi. Pertanto, ho aumentato la "Soglia di costo per il parallelismo" dai nostri standard da 25 a 40 dopo averlo fatto, anche se il carico di lavoro non è cambiato (SELECT / INSERT che si verificano frequentemente) i deadlock sono scomparsi. La mia domanda è: perché?

SPID 356 INSERT ha un blocco IX su una pagina appartenente all'indice non cluster
SPID 690 SELECT ID esecuzione 0 ha un blocco S su una pagina appartenente allo stesso indice non cluster

Adesso

SPID 356 desidera un blocco IX sulla risorsa SPID 690 ma non può raggiungerlo perché SPID 356 è bloccato da SPID 690 ID esecuzione 0 Blocco S ID
SPID 690 esecuzione 1 desidera un blocco S sulla risorsa SPID 356 ma non può ottenerlo perché ID esecuzione 690 SPID 1 è stato bloccato da SPID 356 e ora abbiamo il nostro deadlock.

Il piano di esecuzione è disponibile sul mio SkyDrive

I dettagli completi di deadlock sono disponibili qui

Se qualcuno mi può aiutare a capire perché lo apprezzerei davvero.

Tabella EventReceivers.
Id uniqueidentifier no 16
Nome nvarchar no 512
SiteID uniqueidentifier no 16
WebID uniqueidentifier no 16
HostId uniqueidentifier no 16
HOSTTYPE int no 4
ItemId int no 4
DirName nvarchar no 512
Leafname nvarchar no 256
Tipo int no 4
SequenceNumber int no 4
Assemblea nvarchar no 512
Classe nvarchar no 512
Dati nvarchar no 512
Filtro nvarchar no 512
SourceId tContentTypeId no 512
SourceType int no 4
Credential int no 4
ContextType varbinary no 16
ContextEventType varbinary no 16
ContextId varbinary no 16
ContextObjectId varbinary no 16
ContextCollectionId varbinary no 16

nome_indice index_description index_keys
EventReceivers_ByContextCollectionId cluster situato sulla PRIMARIA SiteID, ContextCollectionId
EventReceivers_ByContextObjectId non cluster trova PRIMARIA SiteID, ContextObjectId
EventReceivers_ById non cluster, unico situato sulla PRIMARIA SiteID, Id
EventReceivers_ByTarget cluster, unico situato sulla PRIMARIA SiteID, WebID, HostId, HOSTTYPE, Tipo, ContextCollectionId, ContextObjectId, ContextId, ContextType, ContextEventType, SequenceNumber, Assembly, Class
EventReceivers_IdUnique chiave non cluster, univoca e univoca situata sull'ID PRIMARY


2
Cosa facciamo proc_InsertEventReceivere proc_InsertContextEventReceivercosa non possiamo vedere nell'XDL? Inoltre, per ridurre il parallelismo, perché non avere un impatto diretto su queste affermazioni (utilizzando MAXDOP 1) invece di fallire con le impostazioni a livello di server?
Aaron Bertrand

1
Sono curioso di sapere qual è la tua vasta impostazione MAXDOP e quanti processori (logici) hai. SharePoint funziona davvero meglio e preferisce essere su un server con un server MAXDOP largo 1 .. Non mi piace, ma è così che lo hanno sviluppato. Puoi pubblicare i piani di esecuzione effettivi? Tutto quello che vedo a quel link è il .xdl (grafico deadlock)
Mike Walsh,

Ciao signori, apprezzo molto il tempo che avete dedicato, fuori dai vostri impegni per rispondere. Pubblicherò sia le procedure che i piani di esecuzione per la tua recensione sul sito SkyDrive. Avevo pensato di modificare il codice per includere l'opzione di query MAXDOP (1), tuttavia, ciò annullerebbe il nostro supporto con Microsoft. Il server fisico è un'impostazione ProLiant DL580 G4 MAXDOP è 4 con un totale di 8 processori fisici e H / T è disabilitato.
SQLJarHead,

Ciao signori, ho creato un pacchetto zip con tutti i dettagli su SkyDrive. Ho modificato il corpo del post originale per includere l'URL del pacchetto. Per favore, non dirmi qual è il problema, basta fornire una guida e farmi lavorare per questo. NOTA: non sono in grado di apportare modifiche al codice o modifiche DDL allo schema sottostante.
SQLJarHead,

1
Quindi, non puoi cambiare il codice e non puoi cambiare lo schema, quali altre soluzioni ti aspetti che escogitare? Se siete preoccupati per invalidare il supporto di Microsoft, allora che implica che si ha il supporto di Microsoft, nel qual caso - dato tutte le restrizioni che ci hai detto che non si può fare - avete considerato l'apertura di un ticket di supporto con Microsoft?
Aaron Bertrand

Risposte:


14

A prima vista, sembra un classico punto morto di ricerca . Gli ingredienti essenziali per questo modello di deadlock sono:

  • una SELECTquery che utilizza un indice non cluster non coprente con una ricerca chiave
  • una INSERTquery che modifica l'indice cluster e quindi l'indice non cluster

Il SELECTaccede l'indice non cluster prima, poi l'indice cluster. L' INSERTaccesso prima all'indice cluster, quindi all'indice non cluster. Accedere alle stesse risorse in un ordine diverso acquisendo blocchi incompatibili è un ottimo modo per 'raggiungere' un punto morto ovviamente.

In questo caso, la SELECTquery è:

SELEZIONA query

... e la INSERTquery è:

INSERISCI query

Si noti la manutenzione degli indici non cluster evidenziata in verde.

Dovremmo vedere la versione seriale del SELECTpiano nel caso in cui sia molto diversa dalla versione parallela, ma come osserva Jonathan Kehayias nella sua guida a Handling Deadlocks , questo particolare modello di deadlock è molto sensibile ai tempi e ai dettagli dell'implementazione interna delle query. Questo tipo di deadlock spesso va e viene senza un ovvio motivo esterno.

Dato l'accesso al sistema interessato e le autorizzazioni adeguate, sono certo che alla fine potremmo capire esattamente perché il deadlock si verifica con il piano parallelo ma non con il seriale (assumendo la stessa forma generale). I potenziali linee di indagine includono il controllo di cicli annidati ottimizzati e / o di prefetching - entrambi i quali possono internamente degenerare il livello di isolamento per REPEATABLE READper tutta la durata della dichiarazione. È anche possibile che alcune caratteristiche dell'assegnazione di intervalli di ricerca di indici paralleli contribuiscano al problema. Se il piano seriale diventa disponibile, potrei passare un po 'di tempo a esaminare ulteriormente i dettagli, poiché è potenzialmente interessante.

La solita soluzione per questo tipo di deadlock è rendere la copertura dell'indice, anche se il numero di colonne in questo caso potrebbe renderlo impraticabile (e inoltre, non dovremmo confondere tali cose su SharePoint, mi è stato detto). In definitiva, la raccomandazione per i piani solo seriali quando si utilizza SharePoint è lì per una ragione (anche se non necessariamente buona, quando si arriva proprio ad esso). Se la modifica della soglia di costo per il parallelismo risolve il problema per il momento, questo è positivo. A più lungo termine, probabilmente cercherei di separare i carichi di lavoro, magari utilizzando Resource Governor in modo che le query interne di SharePoint ottengano il MAXDOP 1comportamento desiderato e l'altra applicazione sia in grado di utilizzare il parallelismo.

La questione degli scambi che appare nella traccia dello stallo mi sembra un'aringa rossa; semplicemente una conseguenza dei thread indipendenti che possiedono risorse che tecnicamente devono apparire nell'albero. Non vedo nulla che suggerisca che gli scambi stessi stiano contribuendo direttamente al problema del deadlock.


6

Se si trattava di un classico deadlock di ricerca , l'elenco delle risorse includerà sia l'indice cluster che l'indice non cluster. In genere, SELEZIONA manterrà un blocco SHARED sull'indice NC e attenderà un blocco SHARED sull'elemento della configurazione, nel frattempo INSERT acquisirà un blocco ESCLUSIVO sull'elemento della configurazione e attenderà un blocco ESCLUSIVO sull'NC. L'elenco delle risorse nel deadlock xml elencherà entrambi questi oggetti in questo caso.

Poiché il grafico del deadlock riguarda solo l'indice NC, possiamo escludere questa opzione.

Inoltre, se si è trattato di un dead dead a causa di Nested Loop Join con UNORDERED PREFETCH , il piano di esecuzione ci dirà se viene utilizzato l'algoritmo UNORDERED PREFETCH, che non è ancora il caso qui (vedi aggiornamento di seguito).

Ciò ci lascia supporre che si tratti di un punto morto dovuto al Piano parallelo.

Il grafico del deadlock non viene visualizzato correttamente, ma se si esamina il deadlock XML, è possibile notare che due deadlock dell'istruzione SELECT (SPID 690) sono coinvolti nel deadlock. Il thread consumer tiene un blocco CONDIVISO su PAGINA 1219645 e attende il produttore su port801f8ed0 (e_waitPipeGetRow). Il thread del produttore è in attesa di un blocco condiviso su PAGINA 1155940.

L'istruzione INSERT sta trattenendo un blocco IX su PAGINA 1155940 e sta aspettando un blocco IX su PAGINA 1219645, causando un deadlock.

Credo che un deadlock verrà evitato quando si utilizza un piano seriale per l'istruzione SELECT poiché in nessun momento richiederà il blocco CONDIVISO su più di una pagina. Penso anche che il piano seriale sarà quasi uguale al piano parallelo (senza l'operatore del parallelismo).

[AGGIORNATO in base al commento di Paul]

Apparentemente il piano utilizza un algoritmo OPTIMIZED Nested Loop

Questo spiega perché i blocchi SHARED vengono mantenuti fino alla fine dell'istruzione. REPEATABLE READ combinato con un piano parallelo è più vulnerabile ai deadlock rispetto a un piano seriale perché il piano parallelo potrebbe acquisire e mantenere blocchi da diversi intervalli di un indice mentre il piano seriale acquisisce blocchi in un modo più sequenziale.


Concordato. Se questo deadlock fosse correlato a un LOOKUP effettivo, la risorsa wait, per SELECT, avrebbe fatto riferimento all'indice cluster. Sono stato in grado di escluderlo visualizzando l'intestazione della pagina per ogni risorsa di attesa (SPID 690 Wait Resource = PAGE: 1155940 | SPID 356 Wait Resource = PAGE 1219645) tramite DBCC PAGE ed entrambi erano sull'ID indice 5 (IndexID 5 = EventReceivers_ByContextObjectId) che punta all'indice NC sulla tabella specificata (EventReceivers).
SQLJarHead

Signori, grazie ancora per aver dedicato del tempo per aiutarvi ad analizzare questo interessante problema. Coppia di domande: 1.) Roji sottolinea che lo SPID parallelo richiede più di una pagina. Non lo vedo in nessuno dei piani di esecuzione. Osservando il numero di righe, per l'operatore INDEX SEEK, solo un thread su due produttori sta elaborando qualsiasi riga. Come hai stabilito che richiedeva più di una pagina? (1/2)
SQLJarHead

2.) Un algoritmo OPTIMIZED Nested Loop imposterà sempre il livello di isolamento su REAPTABLE READ? Ho verificato l'output XML dei piani di esecuzione e vedo solo il commit della lettura per la connessione SPID. Sto assumendo che ciò sia invocato solo a livello di operatore del piano. (2/2)
SQLJarHead

Il comportamento di bloccaggio ottimizzato cicli nidificati è paragonabile a REPEATABLE LEGGI (mantiene i blocchi fino alla fine della dichiarazione ), ma non esplicitamente impostare il livello di isolamento della transazione REPEATABLE LEGGI. Penso che risponda anche alla tua domanda. Non è che i thread paralleli richiedano più di una pagina alla volta, ma un thread parallelo tiene un lucchetto su una pagina e un altro thread è in attesa di un lucchetto su un'altra pagina
Roji P Thomas
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.