Degrado improvviso delle prestazioni di SQL Server


13

Ho un SQL Server 2005 che è diventato imprevedibile negli ultimi tempi e sto grattando la testa sul perché. Le query eseguite in pochi secondi cambiano i piani e richiedono minuti (impiegando il tempo nella scansione della tabella completa o nello spooling dell'indice). Ora la prima e la cosa più ovvia è che le statistiche sono obsolete causando la confusione dell'ottimizzatore, ma sono convinto che non sia così - in primo luogo perché i dati sottostanti non cambiano in modo significativo (ad esempio aggiungendo i dati di un giorno in cima ai dati di un anno già in una tabella) e in secondo luogo perché le statistiche di creazione automatica e di aggiornamento automatico sono entrambe vere. Tuttavia, l'ottimizzatore si sta confondendo; l'esecuzione dell'SQL in Tuning Advisor mi dà molte CREATE STATISTICSistruzioni multi-colonna che sembrano risolverlo (fino a quando il prossimo bit di SQL si comporta male).

Qualche idea di una strategia che posso usare per avvicinarmi a questo? Qual è il motivo per cui le statistiche "normali" non sono sufficienti?

Risposte:


8

Se la tua attesa principale è SOS_SCHEDULER_YIELD, sembrerebbe che tu abbia una certa pressione sulla CPU. Ma questo potrebbe essere il risultato di qualcos'altro, ad esempio il tuo design non è più sufficiente per le tue domande. So che hai detto che stai aggiungendo solo un giorno di dati, ma avresti potuto raggiungere un punto critico.

Come vengono inviate le tue domande? È SQL dinamico? Stai utilizzando le procedure memorizzate? Stai usando sp_executesql? È possibile che tu abbia un caso di sniffing dei parametri? Che aspetto ha il tuo db design? Quali sono le relazioni PK e FK?

Hai un esempio di un buon piano? Se sei in grado di determinare un buon piano, puoi utilizzare le guide del piano per forzare l'esecuzione della query in un modo specifico.

Puoi fare un esempio di un buon piano andato male?

Infine, prendi una copia di sp_whoIsActive ( http://whoisactive.com/ ) da Adam Machanic e usalo per determinare di più sulle query in esecuzione. E se vuoi essere in grado di catturare l'output di sp_whoIsActive, vai qui http://www.littlekendra.com/2011/02/01/whoisactive/


È un'applicazione di terze parti, non ho alcun controllo sul suo schema o SQL, il che è piuttosto orribile, molte query con parametri (ad esempio where col=(cast @var...)) e @varpotrebbero esserlo '%'. L'ho ereditato solo una settimana o due fa e devo mantenerlo sostanzialmente funzionante fino a quando non viene sostituito. Grazie per il link, ci proverò.
Gaio,

La prossima più grande attesa è SOS_SCHEDULER_YIELDstata CXPACKETe sp_configure "max degree of parallelism", 1sembra aver - per ora - bussato entrambi i problemi alla testa. Grazie!
Gaius,

+1 per il link a sp_whoIsActive
Jeff

8

Da MSDN :

"Le operazioni di inserimento si verificano su colonne chiave crescente o decrescente Le statistiche su colonne chiave crescente o decrescente, come le colonne IDENTITY o timestamp in tempo reale, potrebbero richiedere aggiornamenti statistici più frequenti rispetto a Query Optimizer. Le operazioni di inserimento aggiungono nuovi valori a colonne ascendenti o discendenti Il numero di righe aggiunte potrebbe essere troppo piccolo per attivare un aggiornamento delle statistiche Se le statistiche non sono aggiornate e le query selezionano dalle righe aggiunte più di recente, le statistiche correnti non avranno stime di cardinalità per questi nuovi valori. risulta in stime di cardinalità inaccurate e prestazioni lente delle query.

Ad esempio, una query che seleziona tra le date dell'ordine di vendita più recenti avrà stime di cardinalità inaccurate se le statistiche non vengono aggiornate per includere le stime di cardinalità per le date dell'ordine di vendita più recenti.

Dopo le operazioni di manutenzione Considerare l'aggiornamento delle statistiche dopo aver eseguito le procedure di manutenzione che modificano la distribuzione dei dati, come il troncamento di una tabella o l'esecuzione di un inserimento in blocco di una grande percentuale delle righe. Ciò può evitare ritardi futuri nell'elaborazione delle query mentre le query attendono aggiornamenti automatici delle statistiche ".

È possibile utilizzare "EXEC sp_updatestats" di volta in volta sul proprio sistema (programmato di volta in volta) o utilizzare la funzione STATS_DATE su tutti gli oggetti e vedere quando le loro statistiche sono state effettivamente aggiornate l'ultima volta e se da allora è trascorso troppo tempo, utilizzare UPDATE STATISTICHE per quel particolare oggetto. Nella mia esperienza, anche con le statistiche automatiche abilitate, siamo comunque costretti ad aggiornare le statistiche di tanto in tanto, a causa delle operazioni di inserimento che non hanno attivato l'aggiornamento automatico.

Per aggiungere il mio codice personale (utilizzato in un lavoro settimanale che crea dichiarazioni dinamiche per l'aggiornamento delle statistiche):

select distinct
        'update statistics [' + stats.SchemaName + '].[' + stats.TableName + ']'
            + case when stats.RowCnt > 50000 then ' with sample 30 percent;'
            else 
                ';' end
        as UpdateStatement
    from (
        select
            ss.name SchemaName,
            so.name TableName,
            so.id ObjectId,
            st.name AS StatsName, 
            STATS_DATE(st.object_id, st.stats_id) AS LastStatisticsUpdateDate
            , si.RowModCtr
            , (select case si2.RowCnt when 0 then 1 else si2.RowCnt end from sysindexes si2 where si2.id = si.id and si2.indid in (0,1)) RowCnt
        from sys.stats st
            join sysindexes si on st.object_id = si.id and st.stats_id = si.indid
            join sysobjects so on so.id = si.id and so.xtype = 'U' --user table
            join sys.schemas ss on ss.schema_id = so.uid
    ) stats
    where cast(stats.RowModCtr as float)/cast(stats.RowCnt as FLOAT)*100 >= 10 --more than 10% of the rows have changed
    or ( --update statistics that were not updated for more than 3 months (and rows no > 0)
        datediff(month, stats.LastStatisticsUpdateDate, getdate()) >= 3
        and stats.RowCnt > 0
    )

Qui ottengo tutti gli oggetti in cui le statistiche non sono state aggiornate per più di 3 mesi o dall'ultimo aggiornamento delle statistiche ha cambiato più del 10% delle righe.


Hmm, il mio evento di attesa principale è SOS_SCHEDULER_YIELDma non posso dire subito se ciò è dovuto a piani sbagliati, o che questa scatola (6 anni, 2 processori, 4G RAM) è davvero sovraccarica ora e ho superato un punto di non ritorno.
Gaius,

anziché semplicemente eseguire quella query per creare le istruzioni UPDATE ed eseguirle manualmente, è possibile utilizzare un cursore basato sull'istruzione select per eseguire il ciclo circolare dei risultati eseguendoli utilizzando le chiamate a sp_executesql, in questo modo è possibile eseguirlo automaticamente (ad esempio come parte di un piano di manutenzione durante la notte (o altro periodo di quiete)).
David Spillett,

@ David: questo è quello che sto facendo nel lavoro settimanale :). L'ho appena formattato in modo diverso per Gaius per vedere l'output che sto usando. La sceneggiatura iniziale era troppo brutta e lunga. Grazie per l'aiuto con la formattazione! Potete inviarmi a un tutorial di formattazione ... perché non so davvero come rendere bello il codice qui. Grazie!
Marian,

è presente un collegamento "Guida alla formattazione" nella schermata "Modifica risposta" e come icona a destra sopra la casella di risposta iniziale nella pagina principale della domanda, che elenca la sintassi di markdown supportata da questi siti.
David Spillett,

3
Le statistiche di aggiornamento automatico vengono effettivamente attivate al 20% + 500 righe, non al 10%.
mrdenny,

3

La mia ipotesi è che uno o più dei tuoi tavoli stiano diventando abbastanza grandi da non colpire il 20% delle modifiche necessarie per aiutare a contrassegnare le statistiche correnti come obsolete in modo che le statistiche di aggiornamento automatico inizino e tuttavia ci siano abbastanza aggiornamenti (o inserimenti) ) che avere statistiche aggiornate sarebbe di grande aiuto. Recentemente ho trovato la stessa cosa in un ambiente particolare dopo l'aggiornamento da SQL 2000 a SQL 2008.

Oltre agli altri siti citati nelle risposte sopra, suggerirei di consultare le seguenti risorse online.

1) Red-Gate ha una serie di ebook gratuiti disponibili per il download tra cui "SQL Server Statistics" di Holger Schmeling, dove troverai la seguente citazione:

http://www.red-gate.com/our-company/about/book-store/

"le tabelle con più di 500 righe almeno il 20% dei dati di una colonna hanno dovuto essere modificate per invalidare le statistiche collegate"

2) SQL Sentry ha uno strumento gratuito Plan Explorer che aiuta a rintracciare i problemi all'interno di un piano SQL, come una stima di troppe o troppe righe rispetto al numero effettivo di righe per una determinata tabella in una query. Basta salvare il piano di esecuzione effettivo da SSMS e quindi scorrere le diverse parti del piano utilizzando Plan Explorer. Non è che le informazioni non siano disponibili in SSMS utilizzando il piano di esecuzione grafico, ma lo strumento di SQL Sentry rende molto più semplice la visualizzazione.

http://www.sqlsentry.com/plan-explorer/sql-server-query-view.asp

3) Controlla tu stesso la data di aggiornamento delle statistiche per le tabelle nelle query che ti interessano maggiormente utilizzando STATS_DATE (), puoi trovare una query rapida per ottenere le statistiche più vecchie utilizzando una query trovata nella discussione seguente.

http://blog.sqlauthority.com/2010/01/25/sql-server-find-statistics-update-date-update-statistics/

Spero che questo possa essere d'aiuto!

Penso che apprezzerai particolarmente il libro di Red-Gate!

-Jeff


Grazie, lavorerò su quelli. Sono principalmente un DBA Oracle che ha ereditato questo sistema (anche se non ho alcun pregiudizio nei confronti di SQL Server, da quello che vedo dal 2005 è una piattaforma molto capace, non lo so bene come lo so Oracle) .
Gaio,
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.