Query e aggiornamenti estremamente lenti dopo IndexOptimize


12

Database SQL Server 2017 Enterprise CU16 14.0.3076.1

Di recente abbiamo provato a passare dai lavori di manutenzione predefiniti di ricostruzione degli indici a Ola Hallengren IndexOptimize. I lavori predefiniti di ricostruzione degli indici erano in esecuzione da un paio di mesi senza problemi e le query e gli aggiornamenti funzionavano con tempi di esecuzione accettabili. Dopo l'esecuzione IndexOptimizesul database:

EXECUTE dbo.IndexOptimize
@Databases = 'USER_DATABASES',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 5,
@FragmentationLevel2 = 30,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y'

le prestazioni sono state estremamente degradate. Una dichiarazione di aggiornamento che ha richiesto 100 ms prima IndexOptimizeha richiesto 78.000 ms in seguito (utilizzando un piano identico), e le query hanno anche peggiorato diversi ordini di grandezza.

Dato che questo è ancora un database di test (stiamo migrando un sistema di produzione da Oracle) siamo tornati a un backup e disabilitato IndexOptimizee tutto è tornato alla normalità.

Tuttavia, vorremmo capire cosa IndexOptimizefa diversamente dal "normale" Index Rebuildche potrebbe aver causato questo degrado estremo delle prestazioni al fine di assicurarci di evitarlo una volta che andremo in produzione. Qualsiasi suggerimento su cosa cercare sarebbe molto apprezzato.

Piano di esecuzione dell'istruzione di aggiornamento quando è lento. cioè
dopo IndexOptimize
Piano di esecuzione effettivo (disponibile al più presto)

Non sono stato in grado di individuare una differenza.
Pianificare la stessa query quando è veloce
Piano di esecuzione effettivo

Risposte:


11

Ho il sospetto che tu abbia una diversa frequenza di campionamento definita tra i tuoi due approcci di manutenzione. Credo che gli script di Ola utilizzino il campionamento predefinito a meno che non specifichi il @StatisticsSampleparametro , che non sembra che stia facendo attualmente.

A questo punto, questa è una speculazione, ma puoi verificare per vedere quale frequenza di campionamento è attualmente utilizzata nelle tue statistiche eseguendo la seguente query nel tuo database:

SELECT  OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id) AS TableName
    ,   col.name AS ColumnName
    ,   st.name AS StatsName
    ,   sp.last_updated
    ,   sp.rows_sampled
    ,   sp.rows
    ,   (1.0*sp.rows_sampled)/(1.0*sp.rows) AS sample_pct
FROM sys.stats st 
    INNER JOIN sys.stats_columns st_col
        ON st.object_id = st_col.object_id
        AND st.stats_id = st_col.stats_id
    INNER JOIN sys.columns col
        ON st_col.object_id = col.object_id
        AND st_col.column_id = col.column_id
    CROSS APPLY sys.dm_db_stats_properties (st.object_id, st.stats_id) sp
ORDER BY 1, 2

Se vedi che questo sta attraversando un 1s (es. 100%), è questo il tuo problema. Magari prova di nuovo gli script di Ola includendo il @StatisticsSampleparametro con la percentuale che viene restituita da questa query e vedi se questo risolve il tuo problema?


Come ulteriore prova a sostegno di questa teoria, l'XML del piano di esecuzione mostra frequenze di campionamento molto diverse per la query lenta (2.18233%):

<StatisticsInfo LastUpdate="2019-09-01T01:07:46.04" ModificationCount="0" 
    SamplingPercent="2.18233" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

Contro la query veloce (100%):

<StatisticsInfo LastUpdate="2019-08-25T23:01:05.52" ModificationCount="555" 
    SamplingPercent="100" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

@JoshDarnell LOL, questa è la seconda occorrenza in cui hai trovato alcune informazioni sulle statistiche di supporto nel piano di query che non sono riuscito a vedere. Grazie per la modifica!
John Eisbrener,

Haha, ho dimenticato che eri tu, John! Prometto che non ti perseguiterò 😅
Josh Darnell,

@JoshDarnell Apprezzo le intuizioni aggiuntive ed è un altro buon promemoria che ci sono così tante informazioni nei piani di esecuzione che non dovresti saltare.
John Eisbrener,

Felice di aiutare! E sì, ci sono anche cose che mi mancano tutto il tempo (sono stato bruciato dalla cosa delle statistiche, quindi tendo ad andarci rapidamente per vedere cosa succede).
Josh Darnell,

Grazie per questa spiegazione, era davvero il problema. La maggior parte delle statistiche aveva una frequenza di campionamento predefinita del 2,2%, tuttavia alcune create dopo la migrazione da Oracle avevano una frequenza di campionamento del 100%. Sembra che la ricostruzione dell'indice predefinito abbia mantenuto il 100%, ma quando abbiamo usato IndexOptimize ha applicato anche il valore predefinito del 2,2%. Applicare il parametro @StatisticsSample ed eseguire nuovamente le query ha verificato che questo era ciò che aveva causato il problema.
Martin Bergström,

5

La risposta di John è la soluzione corretta, questa è solo un'aggiunta a quali parti del piano di esecuzione sono cambiate e ad esempio su come individuare facilmente le differenze con Sentry One Plan explorer

Una dichiarazione di aggiornamento che ha richiesto 100 ms prima che IndexOptimize impiegasse 78.000 ms in seguito (utilizzando un piano identico)

Quando si esaminano tutti i piani di query quando le prestazioni sono state ridotte, è possibile individuare facilmente le differenze.

Prestazione degradata

inserisci qui la descrizione dell'immagine

Due conteggi di oltre 35 secondi di tempo cpu e tempo trascorso

Prestazioni attese

inserisci qui la descrizione dell'immagine

Molto meglio

Il degrado principale è due volte in questa query di aggiornamento:

UPDATE SVALA.INGÅENDEANALYS
                           SET 
                              UPPDRAGAVSLUTAT = @NEW$AVSLUTAT
                        WHERE INGÅENDEANALYS.ID IN 
                           (
                              SELECT IA.ID
                              FROM 
                                 SVALA.INGÅENDEANALYS  AS IA 
                                    JOIN SVALA.INGÅENDEANALYSX  AS IAX 
                                    ON IAX.INGÅENDEANALYS = IA.ID 
                                    JOIN SVALA.ANALYSMATERIAL  AS AM 
                                    ON AM.ID = IA.ANALYSMATERIALID 
                                    JOIN SVALA.ANALYSMATERIALX  AS AMX 
                                    ON AMX.ANALYSMATERIAL = AM.ID 
                                    JOIN SVALA.INSÄNTMATERIAL  AS IM 
                                    ON IM.ID = AM.INSÄNTMATERIALID 
                                    JOIN SVALA.INSÄNTMATERIALX  AS IMX 
                                    ON IMX.INSÄNTMATERIAL = IM.ID
                              WHERE IM.UPPDRAGSID = SVALA.PKGSVALA$STRIPVERSION(@NEW$ID)
                      )

il piano di esecuzione per questa query con prestazioni degradate

Il piano di query stimato di questa query di aggiornamento ha stime molto elevate in caso di degrado delle prestazioni:

inserisci qui la descrizione dell'immagine

Mentre in realtà (l'attuale piano di esecuzione) deve ancora fare un lavoro, non solo la quantità folle che mostrano le stime.

Il maggiore impatto sulle prestazioni sono le due scansioni e le partite hash che seguono:

Scansione effettiva su prestazioni degradate n. 1

inserisci qui la descrizione dell'immagine

Scansione effettiva su prestazioni degradate n. 2

inserisci qui la descrizione dell'immagine


Il piano di esecuzione per questa query con prestazioni previste

Quando lo si confronta con le stime (o gli effettivi) del piano di query con le prestazioni previste normali, le differenze sono facili da individuare.

inserisci qui la descrizione dell'immagine

Inoltre, i precedenti accessi alle due tabelle non sono nemmeno avvenuti:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Questa eliminazione non viene visualizzata nel join hash perché l'input build (in alto) viene inserito per primo nella tabella hash. Successivamente vengono analizzati valori zero in questa tabella hash, restituendo valori zero.


1
Grazie per la descrizione dettagliata dei piani, è stato molto utile per la mia comprensione del perché si è verificato il problema. Daremo sicuramente un'occhiata a Sentry One Plan Explorer, sembra molto utile!
Martin Bergström,

@ MartinBergström È bello sentirti, grazie per aver fornito i piani di query e averci fornito tutte le informazioni pertinenti di cui abbiamo chiesto nei commenti :). La cosa migliore di Plan Explorer è che è gratis! Può anche funzionare dall'interno di ssms (facendo clic con il pulsante destro del mouse sul piano di esecuzione e premere "Visualizza con Sentryone Plan Explorer").
Randi Vertongen,

1

Senza ulteriori informazioni possiamo prendere solo pugnalate leggermente informate al buio, quindi dovresti modificare la domanda per fornire un po 'di più. Ad esempio, i piani di query per quella dichiarazione di aggiornamento per cui sono stati indicati i tempi, sia prima che dopo le operazioni di manutenzione dell'indice poiché i piani possono differire a causa dell'aggiornamento delle statistiche dell'indice ( https://www.brentozar.com/pastetheplan / è utile per questo, piuttosto che riempire la domanda con quello che potrebbe essere un grosso pezzo di XML o dare una schermata che non include alcune delle informazioni pertinenti contenute nel testo del piano).

Due punti molto semplici fuori dal pipistrello però:

  1. La corsa di ottimizzazione è stata definitivamente completata? Se i tuoi test sono in competizione con l'IO delle ricostruzioni degli indici di lunga durata che influiranno sui tempi.
  2. Hai provato più volte? Se l'aggiornamento si basa sui dati di una query che considera molti dati (piuttosto che un semplice `UPDATE TheTable SET ThisColumn = 'A Static Value'), è possibile che questi dati siano normalmente in memoria ma sono stati cancellati in che le prime esecuzioni delle query correlate saranno più lente del solito a causa del colpire il disco anziché trovare le pagine necessarie già nel pool di buffer in memoria.

Grazie per aver dedicato del tempo per rispondere. Ho aggiornato la domanda con i collegamenti pastetheplan. L'ottimizzazione era definitivamente completata e funzionava per circa 1 ora il giorno prima che si verificassero i problemi. Abbiamo testato più volte e in realtà ha interessato due copie del database in esecuzione in due ambienti di test diversi allo stesso modo. La dichiarazione di aggiornamento era solo l'esempio più semplice che ho trovato, c'erano numerosi altri inserti e selezioni interessate
Martin Bergström,

Con "più volte" intendevo provare gli aggiornamenti più volte dopo un'istanza delle modifiche dell'indice, anziché eseguire lo script di ottimizzazione dell'indice più volte in modo indipendente (anche se questo è di per sé un modo utile per verificare che il risultato sia riproducibile). Se lo svuotamento della memoria è (o fa parte del) problema, i primi aggiornamenti da selezione innescano il pool di buffer in modo che quelli successivi saranno potenzialmente più veloci a causa di un IO significativamente ridotto.
David Spillett,

Mi scuso se la mia risposta non è chiara. Sì, abbiamo provato gli aggiornamenti più volte. I rallentamenti si sono verificati su un database utilizzato dai tester per testare l'applicazione e le query e gli aggiornamenti sono stati eseguiti più volte durante il giorno senza un miglioramento delle prestazioni.
Martin Bergström,
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.