LATCH_EX attende sulla risorsa METADATA_SEQUENCE_GENERATOR


11

Abbiamo un processo che genera un rapporto di inventario. Sul lato client, il processo divide un numero configurabile di thread di lavoro per creare una porzione di dati per il report che corrisponde a un archivio su molti (potenzialmente migliaia, in genere dozzine). Ogni thread di lavoro chiama un servizio Web che esegue una procedura memorizzata.

Il processo del database per l'elaborazione di ogni blocco raccoglie un mucchio di dati in una tabella #Temporary. Alla fine di ogni blocco di elaborazione, i dati vengono scritti in una tabella permanente in tempdb. Infine, al termine del processo, un thread sul lato client richiede tutti i dati dalla tabella permanente tempdb.

Più utenti eseguono questo rapporto, più lentamente diventa. Ho analizzato l'attività nel database. Ad un certo punto, ho visto 35 richieste separate tutte bloccate in un punto del processo. Tutti questi SPID avevano nell'ordine di 50 ms attese di tipo LATCH_EXsulla risorsa METADATA_SEQUENCE_GENERATOR (00000010E13CA1A8). Uno SPID ha questa risorsa e tutti gli altri stanno bloccando. Non ho trovato nulla su questa risorsa di attesa in una ricerca web.

La tabella in tempdb che stiamo usando ha una IDENTITY(1,1)colonna. Questi SPID stanno aspettando la colonna IDENTITY? Quali metodi possiamo usare per ridurre o eliminare il blocco?

Il server fa parte di un cluster. Il server esegue SQL Server 2012 Standard Edition SP1 a 64 bit su Windows 2008 R2 Enterprise a 64 bit. Il server ha 64 GB di RAM e 48 processori, ma il database può usare solo 16 perché è l'edizione standard.

(Si noti che non sono elettrizzato dalla progettazione dell'utilizzo di una tabella permanente in tempdb per contenere tutti questi dati. La modifica sarebbe una sfida tecnica e politica interessante, ma sono aperta a suggerimenti.)

AGGIORNAMENTO 23/04/2013

Abbiamo aperto un caso di supporto con Microsoft. Terrò questa domanda aggiornata man mano che impareremo di più.

AGGIORNAMENTO 5/10/2013

L'ingegnere del supporto di SQL Server ha concordato che le attese sono state causate dalla colonna IDENTITY. La rimozione dell'IDENTITÀ ha eliminato le attese. Non è stato possibile duplicare il problema su SQL 2008 R2; si è verificato solo su SQL 2012.


Il processo essenzialmente copia i dati dalle tabelle #Temporary alla tabella permanente o si sta verificando un'ulteriore logica di trasformazione in quel passaggio?
Jon Seigel,

Nel passaggio che sta aspettando, sta copiando i record di inventario di un singolo negozio nella tabella permanente senza trasformazione. Potremmo operare all'interno della tabella permanente per tutto il tempo, ma penso che il programmatore abbia scelto di utilizzare una tabella temporanea # come area di attesa per impedire che frequenti aggiornamenti dei dati vengano convertiti in blocchi PAGE.
Paul Williams,

Risposte:


4

Supponendo che sia possibile isolare il problema alla generazione di valori di identità (provare a rimuovere quella colonna come test), ciò che consiglierei è questo:

  1. Rimuovere la IDENTITYproprietà dalla colonna nella tabella finale.
  2. Genera valori di identità in ciascuna delle tabelle # temporanee.
  3. Quando si carica la tabella finale, combinare un identificatore numerico per il particolare negozio con i valori di identità del passaggio 2.

Quindi, se hai ID negozio 3 e 4, finiresti con valori ID finali come questo:

3000000001
3000000002
3000000003
...
4000000001
4000000002
...

O qualcosa di simile a quello. Ti viene l'idea.

Ciò eliminerà la necessità di serializzare sulla IDENTITYgenerazione preservando l'unicità nel risultato finale.

In alternativa, a seconda di come funziona il processo, inserire i valori identificativi finali calcolati nelle tabelle #Temporary. Quindi è possibile creare una vista che UNION ALLli unisce, eliminando la necessità di copiare i dati.


Grazie per la risposta. Sono d'accordo se questo è il problema, l'utilizzo di una chiave fabbricata (o nessuna chiave) potrebbe risolverlo. Abbiamo aperto un caso con Microsoft su questo problema. Pubblicherò il risultato qui e accetterò la tua risposta se saranno d'accordo che è il problema.
Paul Williams,

@Paul: Per favore fatemi sapere; Sono altrettanto curioso. Come te, non sono stato in grado di trovare nulla sul web su questo latch, ma è certamente ragionevole che si tratti di serializzazione di identità / sequenza. È difficile dire se questo sia il collo di bottiglia, anche se con oltre 30 thread in competizione per valori, sembra probabile. Puoi anche provare a copiare da ogni tabella temporanea # in serie (anziché in parallelo) per vedere se questo aiuta.
Jon Seigel,

2
L'ingegnere di SQL Server ha concordato che probabilmente era la IDENTITYcolonna. Lo abbiamo rimosso dall'indice cluster già ampio e rimosso completamente la colonna. Non era necessario. Successivamente, queste LATCH_EX attese sono andate via. Non è stato possibile duplicare le attese su SQL 2008 R2. Il problema si è verificato solo su SQL Server 2012.
Paul Williams,

@Paul: grazie per il follow-up. Molto interessante. Immagino che il codice che genera IDENTITYvalori sia stato riscritto per usare la nuova generazione di sequenze che era nuova nel 2012. Su <2012, potresti vedere un diverso tipo di latch, anche se se non ci fosse un problema perf, allora sembra che ci fosse una regressione nel codice. In ogni caso, rimuovere la IDENTITYcolonna è la cosa più sicura.
Jon Seigel,

Invece di identità potresti provare a usare una "SEQUENZA" (che è nuova in SQL 2012)
Bogdan Maxim

7

(Aggiornato febbraio 2019)

Questo è un vecchio post, che diceva che sono finalmente riuscito a convincere Microsoft che il fatto stesso che ciò accada è davvero un difetto.

Aggiornamento: MS ha confermato il difetto e gli ha assegnato un bug n. 12628722.

Avevo visto questo post lo scorso novembre 2018 quando abbiamo iniziato a soffrire più o meno lo stesso dopo aver eseguito l'aggiornamento da SQL Server 2005 a SQL Server 2017. Una tabella di 3,3 milioni di righe che impiegava 10 secondi per l'inserimento di massa ha iniziato improvvisamente a prendere 10 minuti su tabelle con Identitycolonne.

Si scopre che ci sono due problemi dietro questo:

  1. Microsoft ha modificato il comportamento in SQL Server 2014 per forzare l'esecuzione in parallelo degli inserti in blocco: nelle versioni precedenti gli inserti in blocco avevano un piano serializzato.
  2. Una volta in esecuzione in parallelo sulla nostra scatola da 32 core, il motore ha trascorso più tempo con i nuclei bloccati a vicenda piuttosto che fare effettivamente il lavoro.

Mi ci sono voluti 4 settimane, ma subito dopo le vacanze ho ricevuto un regalo in ritardo da Babbo Natale - la conferma che il problema era davvero un difetto.

Ci sono alcune possibili soluzioni che abbiamo trovato fino a quando questo non è stato risolto:

  1. Utilizzare Option (MaxDop 1)nella query per trasformare l'inserto di massa in un piano serializzato.
  2. Maschera la colonna Identità lanciandola (ad es. Select Cast(MyIdentityColumn As Integer) As MyIdentityColumn)
    • questo impedisce di copiare la proprietà identità durante l'utilizzo SELECT...INTO
  3. Rimuovere la colonna identità come descritto sopra.
  4. Modificare la modalità di compatibilità del database su SQL Server 2012 o precedente per ristabilire un piano serializzato.

Aggiornamento: la correzione che verrà implementata da MS sarà quella di riportare questo tipo di inserti a utilizzare un Serialized piano. Questo è previsto per Sql Server 2017 CU14 (nessuna notizia su altre versioni di Sql Server - scusate!). Una volta implementato, Trace Flag 9492 dovrà essere attivato, a livello di server o tramite DBCC TraceOn .

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.