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

Sintonizzazione delle prestazioni Knee-Jerk:uso scorretto di tabelle temporanee

In questa continuazione della mia serie "regolazione delle prestazioni a scatti", vorrei discutere quattro problemi comuni che vedo con l'utilizzo di tabelle temporanee. Ognuno di questi problemi può paralizzare un carico di lavoro, quindi vale la pena conoscerli e cercarli nel tuo ambiente.

Problema 1:utilizzo di tabelle temporanee dove non sono necessarie

https://www.flickr. com/photos/tea_time/3890677277/

Le tabelle temporanee hanno una varietà di usi (probabilmente il più comune è memorizzare un set di risultati intermedio per un uso successivo), ma devi ricordare che quando introduci una tabella temporanea in una query, stai interrompendo il flusso di dati attraverso il elaboratore di query.

Pensa al popolamento di una tabella temporanea come a un arresto forzato, poiché c'è una query (chiamiamola produttore) per produrre il set di risultati intermedio, che viene quindi archiviato nella tabella temporanea in tempdb, e quindi la query successiva (chiamiamola se il consumatore) deve leggere nuovamente i dati dalla tabella temporanea.

Ho spesso riscontrato che alcune parti di un carico di lavoro funzionano effettivamente meglio quando la tabella temporanea viene completamente rimossa, quindi i dati fluiscono dalla parte producer della query alla parte consumer della query senza dover essere mantenuti in tempdb e il Query Optimizer può produrre un piano generale più ottimale.

Ora potresti pensare "quindi perché qualcuno dovrebbe usare una tabella temporanea se rende le cose più lente?" – e giustamente! In casi del genere, ho scoperto che l'uso di una tabella temporanea è stato istituzionalizzato nel team di sviluppo; qualcuno ha scoperto che l'utilizzo di una tabella temporanea ha aumentato le prestazioni molti anni fa, quindi le tabelle temporanee sono diventate la scelta di progettazione predefinita.

Questa può essere una cosa difficile da cambiare, soprattutto se hai uno sviluppatore o manager senior convinto che le tabelle temporanee dovrebbero essere sempre utilizzate. La cosa semplice da provare è scegliere una query costosa (ad esempio, una query di lunga durata o eseguita più volte al secondo) e rimuovere una o più tabelle temporanee per vedere se le prestazioni aumentano senza di esse. E se è così, c'è la tua prova per mostrare gli intransigenti!

Problema 2:mancanza di filtri durante il popolamento di tabelle temporanee

Anche se non puoi rimuovere una tabella temporanea, potresti essere in grado di migliorare drasticamente le prestazioni assicurandoti che il codice che popola la tabella temporanea stia filtrando correttamente i dati estratti dalle tabelle di origine.

Ho perso il conto del numero di volte in cui ho visto una tabella temporanea popolata con codice che inizia come SELECT * , include alcuni join non restrittivi e non ha alcuna clausola WHERE, quindi la query successiva che utilizza la tabella temporanea utilizza solo poche colonne e dispone di una clausola WHERE per ridurre notevolmente il numero di righe.

Ricordo un caso in cui una tabella temporanea in una stored procedure aggregava 15 anni di dati dal database principale e quindi venivano utilizzati solo i dati dell'anno corrente. Ciò causava ripetutamente l'aumento di tempdb fino all'esaurimento dello spazio sul volume del disco e la procedura memorizzata non riusciva.

Ogni volta che si compila una tabella temporanea, utilizzare solo le colonne della tabella di origine necessarie e utilizzare solo le righe necessarie, ovvero inserire i predicati del filtro nel codice di popolamento della tabella temporanea. Non solo questo consentirà di risparmiare spazio in tempdb, ma farà anche risparmiare molto tempo dal non dover copiare i dati non necessari dalla tabella di origine (e potenzialmente rimuovere la necessità di leggere le pagine del database di origine dal disco in primo luogo).

Problema 3:indicizzazione temporanea della tabella errata

Proprio come con le tabelle normali, è necessario creare solo gli indici che verranno effettivamente utilizzati dal codice di query successivo per migliorare le prestazioni della query. Ho visto molti casi in cui è presente un indice non cluster per colonna della tabella temporanea e gli indici a colonna singola scelti senza analizzare il codice successivo sono spesso abbastanza inutili. Ora combina gli indici non cluster inutili con la mancanza di filtri durante il popolamento della tabella temporanea e hai una ricetta per un enorme rigonfiamento di tempdb.

Inoltre, in generale, è più veloce creare gli indici dopo che la tabella è stata popolata. Ciò offre il vantaggio aggiuntivo che gli indici avranno statistiche accurate, che possono aiutare ulteriormente la query poiché Query Optimizer sarà in grado di eseguire una stima accurata della cardinalità.

Avere un mucchio di indici non cluster che non vengono utilizzati spreca non solo spazio su disco, ma anche il tempo necessario per crearli. Se si trova nel codice che viene eseguito di frequente, la rimozione di questi indici non necessari creati ogni volta che viene eseguito il codice può avere un effetto significativo sulle prestazioni complessive.

Problema 4:contesa sul latch di tempdb

È abbastanza comune che in tempdb si verifichi un collo di bottiglia che può essere ricondotto all'utilizzo temporaneo della tabella. Se sono presenti molte connessioni simultanee che eseguono codice che crea ed elimina tabelle temporanee, l'accesso alle bitmap di allocazione del database in memoria può diventare un collo di bottiglia significativo.

Questo perché solo un thread alla volta può modificare una bitmap di allocazione per contrassegnare le pagine (dalla tabella temporanea) come allocate o deallocate e quindi tutti gli altri thread devono attendere, diminuendo il throughput del carico di lavoro. Anche se esiste una cache di tabella temporanea da SQL Server 2005, non è molto grande e ci sono restrizioni su quando la tabella temporanea può essere memorizzata nella cache (ad esempio solo quando ha una dimensione inferiore a 8 MB).

I metodi tradizionali per aggirare questo problema sono stati l'utilizzo del flag di traccia 1118 e più file di dati tempdb (per ulteriori informazioni, vedere questo post del blog), ma un'altra cosa da considerare è rimuovere del tutto le tabelle temporanee!

Riepilogo

Le tabelle temporanee possono essere molto utili, ma sono molto facilmente e comunemente usate in modo errato. Ogni volta che scrivi (o rivedi codice) utilizzando una tabella temporanea, considera quanto segue:

  • Questa tabella temporanea è veramente necessaria ?
  • È il codice che popola la tabella utilizzando il filtro corretto limitare le dimensioni temporanee della tabella?
  • Gli indici vengono creati dopo il popolamento della tabella (in generale) e sono gli indici utilizzati con codice successivo?

Paul White ha un paio di ottimi post (qui e qui) sull'utilizzo di oggetti temporanei e sulla memorizzazione nella cache che consiglio di leggere anche.

E un'ultima cosa, se decidi di non utilizzare una tabella temporanea, non sostituirla semplicemente con una variabile di tabella, un'espressione di tabella comune o un cursore (tutti modi comuni con cui le persone cercano di "ottimizzare" il tabella temporanea) – trova il modo più efficiente per (ri)scrivere il codice – non esiste una risposta "taglia unica".

Alla prossima volta, buona risoluzione dei problemi!