Database
 sql >> Database >  >> RDS >> Database

Statistiche di attesa sbalorditive:PAGELATCH

Negli ultimi 18 mesi mi sono concentrato sulle reazioni istintive per attendere, analisi statistiche e altri argomenti relativi all'ottimizzazione delle prestazioni, e in questo post continuerò e discuterò il PAGELATCH_XX aspetta. I XX alla fine dell'attesa indicano che esistono più tipi di PAGELATCH wait, e gli esempi più comuni sono:

  • PAGELATCH_SH – ( SH sono) in attesa di accedere a una pagina di un file di dati in memoria in modo che il contenuto della pagina possa essere letto
  • PAGELATCH_EX o PAGELATCH_UP – (EX clusive o UP data) in attesa di accedere ad una pagina di un file di dati in memoria per poter modificare il contenuto della pagina

Quando uno di questi tipi di attesa è il più diffuso su un server, la reazione istintiva è che il problema ha a che fare con l'I/O (cioè la confusione con PAGEIOLATCH_XX wait type, di cui ho parlato in un post nel 2014) e qualcuno prova ad aggiungere più memoria o a modificare il sottosistema di I/O. Nessuna di queste reazioni avrà alcun effetto, poiché le pagine dei file di dati in conflitto sono già in memoria nel pool di buffer!

In tutti i casi, puoi vedere se hai un problema con PAGELATCH_XX contesa utilizzando sys.dm_os_waiting_tasks script sul mio blog o utilizzando uno strumento come Performance Advisor, come dimostrato (per un diverso tipo di attesa) in questo post.

Allora, qual è la fonte della contesa? Per prima cosa spiegherò lo sfondo dietro questi tipi di attesa, quindi discuterò le due cause più comuni di PAGELATCH_XX contesa.

Sfondo:fermi

Prima di entrare in alcune delle cause di PAGELATCH_XX aspetta, voglio spiegare perché esistono.

In qualsiasi sistema multi-thread, le strutture di dati a cui è possibile accedere e manipolare da più thread devono essere protette per prevenire scenari come:

  • Due thread che aggiornano una struttura dati contemporaneamente e alcuni aggiornamenti vengono persi
  • Un thread che aggiorna una struttura dati in concomitanza con un altro thread che legge la struttura dati, in modo che il thread di lettura veda una combinazione di dati vecchi e nuovi

Questa è informatica di base e SQL Server non è diverso, quindi tutte le strutture di dati all'interno di SQL Server devono avere il controllo dell'accesso multi-thread.

Uno dei meccanismi utilizzati da SQL Server per eseguire questa operazione è chiamato latch, in cui tenere il latch in modalità esclusiva impedisce ad altri thread di accedere alla struttura dei dati e mantenere il latch in modalità di condivisione impedisce ad altri thread di modificare la struttura dei dati. SQL Server utilizza anche gli spinlock per alcune strutture di dati e ne ho discusso in questo post nel 2014.

Ma perché una pagina di un file di dati in memoria è protetta da un latch, potresti chiederti? Bene, una pagina di file di dati è solo una struttura di dati, anche se per scopi speciali, e quindi necessita degli stessi controlli di accesso di qualsiasi altra struttura di dati. Quindi, quando un thread deve modificare una pagina di un file di dati, deve acquisire un latch esclusivo o di aggiornamento sulla pagina e, se non può e deve attendere, il tipo di attesa PAGELATCH_EX o PAGELATCH_UP risultati.

Contesa classica per tempdb

PAGELATCH la contesa in tempdb è in genere su bitmap di allocazione e si verifica con carichi di lavoro con molte connessioni simultanee che creano ed eliminano piccole tabelle temporanee (che sono archiviate in tempdb).

Quando la prima riga viene inserita in una tabella temporanea, devono essere allocate due pagine (una pagina dati e una pagina IAM, che tiene traccia della pagina dati). Queste pagine devono essere contrassegnate come allocate in una pagina di allocazione speciale chiamata pagina PFS e per impostazione predefinita sono allocate da estensioni di dati speciali che vengono tracciate da un'altra pagina di allocazione chiamata pagina SGAM (i dettagli di queste possono essere trovati nel mio vecchio post del blog qui). Quando la tabella temporanea viene eliminata, queste pagine devono essere nuovamente deallocate, rendendo necessarie ulteriori modifiche alle pagine PFS e SGAM.

Se le tabelle temporanee sono piccole e la dimensione cumulativa di tutte le tabelle temporanee create contemporaneamente è inferiore a 64 MB, tutte queste modifiche alle bitmap di allocazione sono centrate sulle primissime pagine PFS e SGAM nel file di dati tempdb (con ID pagina (1:1) e (1:3) rispettivamente). L'aggiornamento di una di queste pagine di allocazione richiede il blocco della pagina e solo un thread alla volta può modificare la pagina, quindi tutti gli altri thread devono attendere, con il tipo di attesa PAGELATCH_UP .

Da SQL Server 2005 in poi, le tabelle temporanee possono essere memorizzate nella cache quando vengono eliminate, purché abbiano una dimensione inferiore a 8 MB (e in SQL Server 2014 non vengono create in una stored procedure che dispone anche di istruzioni DDL nella tabella temporanea). Ciò significa che il thread successivo che esegue lo stesso piano di query può rimuovere la tabella temporanea dalla cache e non dover gestire le allocazioni iniziali. Ciò riduce la contesa sulle bitmap di allocazione, ma la cache della tabella temporanea non è molto grande, quindi i carichi di lavoro con centinaia di creazione/rimozione simultanea di tabelle temporanee vedranno comunque molta contesa.

È banale prevenire la contesa sulle pagine SGAM in tempdb abilitando il flag di traccia documentato 1118 sul server, che dico dovrebbe essere abilitato su tutti i server in tutto il mondo, ed è in realtà il comportamento predefinito non modificabile in SQL Server 2016.

Prevenire la contesa nelle pagine PFS in tempdb è un po' più difficile. Supponendo che le tabelle temporanee siano necessarie per le prestazioni, il trucco consiste nell'avere più file di dati per tempdb in modo che le allocazioni vengano eseguite round-robin tra i file, la contesa viene suddivisa su più pagine PFS e quindi la contesa generale diminuisce. Sfortunatamente non esiste una risposta giusta per quanti file di dati dovresti avere. Puoi leggere ulteriori informazioni sulla guida generalmente accettata su questo nell'articolo della Knowledge Base 2154845 e in questo post del blog.

Inserisci hotspot

Nei database degli utenti, una causa comune dell'alto numero di PAGELATCH_EX waits è un hotspot di inserimento.

Ciò può verificarsi quando una tabella ha un indice cluster con una chiave cluster int o bigint e una dimensione della riga sufficientemente piccola da consentire a molte decine o più righe di tabella di rientrare in una pagina dati a livello di foglia dell'indice cluster.

Per tale tabella, se il carico di lavoro coinvolge molte decine o centinaia di thread simultanei inseriti nella tabella, molti thread genereranno righe con valori di identità (e quindi chiavi cluster) che devono essere inserite nella stessa pagina di dati a livello di foglia .

Ora ricorda che apportare qualsiasi modifica a una pagina di un file di dati in memoria richiede un latch esclusivo, quindi ciascuno dei thread che tenta di inserirsi nella stessa pagina deve acquisire esclusivamente il latch della pagina. Mentre ogni thread tiene il latch esclusivo, gli altri thread attenderanno PAGELATCH_EX per quella pagina, essenzialmente trasformando gli inserimenti simultanei in un processo sincrono estremamente collo di bottiglia.

Ci sono alcune possibili soluzioni per questo problema:

  • Utilizza una chiave più casuale e riconosci che ciò comporterà la frammentazione dell'indice, quindi utilizza anche un fattore di riempimento dell'indice per prevenire le divisioni di pagina
  • Distribuisci gli inserti nella tabella usando una sorta di meccanismo di partizionamento artificiale
  • Usa una dimensione della riga della tabella più lunga (questa è ovviamente l'opzione meno appetibile)

Ho visto un hotspot di inserimento come questo spuntare quando qualcuno ha provato a rimuovere i problemi di frammentazione dell'indice modificando una chiave del cluster GUID casuale in una chiave del cluster di identità int o bigint, ma non è riuscito a testare il nuovo schema della tabella sotto carichi di produzione.

Riepilogo

Proprio come con altri tipi di attesa, capire esattamente cosa PAGELATCH_XX waits mean è la chiave per capire come risolverli.

Per quanto riguarda le statistiche generali sull'attesa, puoi trovare ulteriori informazioni sull'utilizzo per la risoluzione dei problemi relativi alle prestazioni in:

  • Le mie serie di post sul blog SQLskills, a partire dalle statistiche di attesa, o per favore dimmi dove fa male
  • La mia libreria Tipi di attesa e classi Latch qui
  • Corso di formazione online My Pluralsight SQL Server:risoluzione dei problemi relativi alle prestazioni utilizzando le statistiche di attesa
  • Consigliere prestazioni SQL Sentry

Alla prossima volta, buona risoluzione dei problemi!