Quando una query SQL precedentemente veloce inizia a funzionare lentamente, dove posso cercare l'origine del problema?


37

sfondo

Ho una query in esecuzione su SQL Server 2008 R2 che unisce e / o unisce a sinistra circa 12 "tabelle" diverse. Il database è abbastanza grande con molte tabelle di oltre 50 milioni di righe e circa 300 tabelle diverse. È per un'azienda di grandi dimensioni che ha 10 magazzini in tutto il paese. Tutti i magazzini leggono e scrivono nel database. Quindi è piuttosto grande e piuttosto occupato.

La query con cui ho problemi è simile a questa:

select t1.something, t2.something, etc.
from Table1 t1
    inner join Table2 t2 on t1.id = t2.t1id
    left outer join (select * from table 3) t3 on t3.t1id = t1.t1id
    [etc]...
where t1.something = 123

Si noti che uno dei join si trova su una query secondaria non correlata.

Il problema è che a partire da questa mattina, senza alcuna modifica (che io o qualcuno del mio team conosciamo) al sistema, la query che richiede normalmente circa 2 minuti per l'esecuzione, ha iniziato a richiedere un'ora e mezza per l'esecuzione, quando corse a tutti. Il resto del database ronza bene. Ho rimosso questa query dallo sproc in cui di solito viene eseguita e l'ho eseguita in SSMS con variabili di parametro codificate con la stessa lentezza.

La stranezza è che quando prendo la sottoquery non correlata e la butto in una tabella temporanea, e quindi uso quella invece della sotto-query, la query funziona correttamente. Inoltre (e questo è il più strano per me) se aggiungo questo pezzo di codice alla fine della query, la query funziona alla grande:

and t.name like '%'

Ho concluso (forse in modo errato) da questi piccoli esperimenti che la ragione del rallentamento è dovuta alla configurazione del piano di esecuzione memorizzato nella cache di SQL: quando la query è leggermente diversa, deve creare un nuovo piano di esecuzione.

La mia domanda è questa: quando una query che era in esecuzione veloce inizia improvvisamente a funzionare lentamente nel cuore della notte e nient'altro è interessato tranne questa query, come posso risolverla e come posso evitare che accada in futuro ? Come faccio a sapere cosa sta facendo SQL internamente per renderlo così lento (se la query errata viene eseguita, potrei ottenere il suo piano di esecuzione ma non funzionerà - forse il piano di esecuzione previsto mi darebbe qualcosa?)? Se questo problema riguarda il piano di esecuzione, come posso impedire a SQL di pensare che piani di esecuzione davvero scadenti siano una buona idea?

Inoltre, questo non è un problema con lo sniffing dei parametri. L'ho già visto prima, e non è così, dato che anche quando codifico le variabili in SSMS, ottengo comunque prestazioni lente.


Potresti condividere il piano di query (quello lento) qui: brentozar.com/pastetheplan
MJH,

Risposte:


32

Quando una query che correva veloce inizia improvvisamente a funzionare lentamente nel cuore della notte e nient'altro è interessato tranne questa query, come posso risolverla ...?

Puoi iniziare controllando se il piano di esecuzione è ancora nella cache. Controllare sys.dm_exec_query_stats, sys.dm_exec_procedure_statse sys.dm_exec_cached_plans. Se il piano di esecuzione errato è ancora memorizzato nella cache, puoi analizzarlo e puoi anche controllare le statistiche di esecuzione. Le statistiche di esecuzione conterranno informazioni come letture logiche, tempo della CPU e tempo di esecuzione. Questi possono dare forti indicazioni su quale sia il problema (ad es. Scansione di grandi dimensioni contro blocco). Vedere Identificazione delle query dei problemi per una spiegazione su come interpretare i dati.

Inoltre, questo non è un problema con lo sniffing dei parametri. L'ho già visto prima, e non è così, dato che anche quando codifico le variabili in SSMS, ottengo comunque prestazioni lente.

Non sono convinto. Le variabili hard-coding in SSMS non dimostrano che il precedente piano di esecuzione errata non è stato compilato in base a un input distorto. Si prega di leggere le opzioni Sniffing, Embedding e RECOMPILE dei parametri per un ottimo articolo sull'argomento. Lento nell'applicazione, veloce in SSMS? Comprendere i misteri delle prestazioni è un altro riferimento eccellente.

Ho concluso (forse in modo errato) da questi piccoli esperimenti che la ragione del rallentamento è dovuta alla configurazione del piano di esecuzione memorizzato nella cache di SQL: quando la query è leggermente diversa, deve creare un nuovo piano di esecuzione.

Questo può essere facilmente testato. SET STATISTICS TIME ONti mostrerà il tempo di compilazione vs. di esecuzione. SQL Server: i contatori delle prestazioni delle statistiche riveleranno anche se la compilazione è un problema (francamente, lo trovo improbabile).

Tuttavia, c'è qualcosa di simile che potresti colpire: la query grant gate. Leggi Informazioni sulla concessione della memoria del server SQL per i dettagli. Se la query richiede una grande concessione in un momento, non è disponibile memoria, dovrà attendere e apparirà come "esecuzione lenta" per l'applicazione. L'analisi delle statistiche sulle informazioni di attesa rivelerà se questo è il caso.

Per una discussione più generale su cosa misurare e cosa cercare, vedere Come analizzare le prestazioni di SQL Server


7

Questa è una rovina dell'esecuzione di query complesse in SQL Server. Fortunatamente, non succede così spesso.

Guarda il piano di query per la query (quando è lento). Immagino che troverai un join di loop nidificato che si verifica una o più volte su tabelle senza indici per il join. Questo rallenta davvero le cose. Per avanzare rapidamente, il modo per risolvere questo problema è con un suggerimento. Aggiungere quanto segue alla fine della query:

OPTION (MERGE JOIN, HASH JOIN)

Questo ha generalmente risolto questo problema per me in passato.

Ciò che potrebbe accadere è che sottili modifiche alla tabella (o alla disponibilità di spazio temporaneo) fanno sì che l'ottimizzazione SQL preferisca un algoritmo di join più lento. Questo può essere abbastanza sottile e piuttosto improvviso. Quando si crea una tabella temporanea, l'ottimizzatore ha più informazioni sulla tabella (come le sue dimensioni), in modo da poter generare un piano migliore.


1
Il piano di esecuzione sta effettivamente utilizzando un join loop nidificato. Tuttavia, quando inserisco il suggerimento come suggerito, viene visualizzato questo errore: "Il processore di query non è stato in grado di produrre un piano di query a causa dei suggerimenti definiti in questa query. Reinvia la query senza specificare alcun suggerimento e senza utilizzare SET FORCEPLAN." Quando aggiungo OPTION (LOOP JOIN), ovviamente, verrà creato un piano di esecuzione, ma ho ancora problemi a farlo funzionare lentamente. Hai riscontrato questo problema? Sembra che abbia BISOGNO di unirsi in loop.

@Trevor. . . No, in realtà non ho visto questo problema. Forse la tua query sta eseguendo alcuni non-equijoin (non usando segni di uguale) e l'ottimizzatore deve usare i collegamenti loop nidificati lì.
Gordon Linoff

3

Di solito è un indice mancante che causa questo tipo di problema.

Quello che faccio di solito è eseguire la query utilizzando SQL Management Studio e abilitare "Includi piano di esecuzione effettivo (CTRL + M)" e scoprire quale join ha la percentuale maggiore.

L'applicazione non si concentra sul collo di bottiglia, ma puoi trovarla "rapidamente" solo guardando il risultato.

esempio qui: 48PercentForTop


2
un indice non andrà improvvisamente "mancante", quindi, sebbene ciò possa migliorare le prestazioni, non spiega il problema
Fowl,

3

Di recente ho riscontrato questo stesso problema che mi ha portato a questa pagina.

@MartinSmith era interessato a qualcosa quando ha raccomandato di aggiornare le tue statistiche e spiegare il piano. Vorrei aggiungere che dovresti anche cercare di assicurarti di dare un'occhiata ai lavori / query in esecuzione che possono creare blocchi e quindi rallentare i tempi di risposta.

Nel mio caso il colpevole era il lavoro di raccolta delle statistiche sul tavolo. Per qualche motivo non si completava nella finestra che avrebbe dovuto e continuava a funzionare quando gli utenti avevano ripreso. Ho trovato il processo, l'ho ucciso e le domande hanno ripreso a rispondere.

spero che questo aiuti qualcun'altro


0

È inoltre necessario verificare se è in esecuzione alcun backup del server o processi di archiviazione \ indicizzazione quando si riscontra un problema di prestazioni in T-SQL \ Procedura.

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.