Le istruzioni di SQL Server rallentano in modo intermittente su SQL Server 2008 R2


13

Su uno dei nostri clienti, abbiamo riscontrato alcuni problemi di prestazioni nella nostra applicazione. È un'app Web .NET 3.5 che utilizza e aggiorna i dati su un database SQL Server. Attualmente il nostro ambiente di produzione è costituito da un computer Windows 2008 R2 come front-end e da un cluster SQL Server 2008 R2 sul back-end. La nostra app utilizza COM + e MSDTC per connettersi al database.

Ecco cosa sta succedendo: i nostri utenti finali a volte lamentano lentezza nell'applicazione. Il caricamento di alcune pagine richiede più tempo del previsto. Durante il tentativo di capire cosa sta succedendo, sono riuscito a scoprire alcuni strani comportamenti sul lato del database che potrebbero essere la causa del degrado delle prestazioni. Ho notato che a volte ci sono alcune istruzioni SQL che richiedono molto più tempo per eseguire ciò che ci si aspetterebbe. Sono riuscito a identificare alcune di queste affermazioni (principalmente sono invocazioni di alcune delle procedure memorizzate della nostra applicazione) utilizzando una traccia del profiler (con il modello TSQL_Duration) per identificare le query di lunga durata.

Il problema è che quando eseguo queste procedure memorizzate direttamente sul database su SQL Management Studio a volte impiegano molto tempo (circa 7/8 secondi), altre volte sono veloci (meno di 1 secondo). Non so perché questo accada e mi sta facendo impazzire, perché la macchina SQL (4 core, 32 GB) non viene utilizzata da altre applicazioni e queste query non dovrebbero richiedere così tanto tempo per essere eseguite.

Non essendo un DBA o un guru di SQL Server, ho cercato di esaminare alcune cose che potrebbero aiutarmi a capire il problema. Ecco i passaggi che ho preso per cercare di risolvere il problema e quello che ho scoperto finora:

  • Tutto il codice TSQL chiamato dall'applicazione è scritto in stored procedure.
  • Ho identificato alcune delle query a esecuzione prolungata sul profiler di SQL Server, tuttavia quando le eseguo su Management Studio impiegano molto tempo per l'esecuzione (da 4 a 10 secondi) o l'esecuzione rapida (meno di 1 secondo). Sto eseguendo le stesse identiche query con gli stessi dati passati nei parametri. Queste query sono principalmente stored procedure con istruzioni selezionate in esse.
  • Ho provato a guardare le statistiche di attese e code per cercare di capire se ci sono processi in attesa su alcune risorse. Ho eseguito la seguente query:

WITH Waits AS
    (SELECT
        wait_type,
        wait_time_ms / 1000.0 AS WaitS,
        (wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
        signal_wait_time_ms / 1000.0 AS SignalS,
        waiting_tasks_count AS WaitCount,
        100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS Percentage,
        ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS RowNum
    FROM sys.dm_os_wait_stats
    WHERE wait_type NOT IN (
        'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
        'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
        'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',  'BROKER_TO_FLUSH',
        'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT',     'DISPATCHER_QUEUE_SEMAPHORE',
        'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
        'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
        'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
        'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
        'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
    )
SELECT
    W1.wait_type AS WaitType, 
    CAST (W1.WaitS AS DECIMAL(14, 2)) AS Wait_S,
    CAST (W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S,
    CAST (W1.SignalS AS DECIMAL(14, 2)) AS Signal_S,
    W1.WaitCount AS WaitCount,
    CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage,
    CAST ((W1.WaitS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgWait_S,
    CAST ((W1.ResourceS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgRes_S,
    CAST ((W1.SignalS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgSig_S
FROM Waits AS W1
    INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount,    W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95; -- percentage threshold
GO

Ecco cosa ho scoperto:

  • Dopo aver ripristinato le statistiche utilizzando DBCC SQLPERF (circa 1 o 2 ore dopo), i tipi di attesa che ho di più sono SOS_SCHEDULER_YIELD e WRITELOG
  • Nel tempo (dopo circa 1 giorno di esecuzione), i tipi di attesa che si verificano maggiormente nel database sono CXPACKET (67%) e OLEDB (17%), anche se il tempo medio di attesa per ciascuno non è lungo. Ho anche notato che le istruzioni più lunghe identificate su SQL Profiler sono chiamate a procedure memorizzate che restituiscono più di un gruppo di risultati (spesso 3). Può esserci un problema di paralellismo qui? Esiste un modo per provare a identificare se questa è la causa del problema?
  • Ho letto da qualche parte che le attese di OLEDB possono essere causate da chiamate a risorse OLEDB come server collegati. Abbiamo un server collegato per connetterci con una macchina dei servizi di indicizzazione (MSIDXS), tuttavia nessuna delle dichiarazioni identificate come di lunga durata fa uso di quel server collegato.
  • Il tempo di attesa medio più alto che ho è per le attese di tipo LCK_M_X (circa 1,5 secondi in media), ma questi tipi di attesa non si verificano molto spesso rispetto ad altri tipi (ad esempio, 64 LCK_M_X attende rispetto a 10.823 CXPACKET attende nello stesso periodo di tempo ).
  • Una cosa che ho notato è che il servizio MSDTC non è cluster. Il servizio SQL Server è in cluster ma non MSDTC. Può esserci un successo nelle prestazioni a causa di questo? Stiamo utilizzando MSDTC perché la nostra app utilizza Enterprise Services (DCOM) per accedere al database, ma i server non sono stati installati e configurati da noi, ma dal nostro client.

Qualcuno può aiutarmi a dare un po 'più di senso a questi dati? Qualcuno può darmi una mano per capire cosa può succedere? C'è qualcosa che posso fare sul server per provare a capire le cose? Devo parlare con il team di sviluppo delle applicazioni?

Risposte:


4

Grazie per la spiegazione dettagliata del tuo problema (una delle domande meglio presentate in realtà).

WRITELOG è un tipo di attesa molto comune, quindi non preoccuparti. Osservando SOS_SCHEDULER_YIELD indica la pressione della CPU e anche CXPACKET, è possibile che vi siano alcuni indici mancanti e che si stiano recuperando molti dati dalle query per un sistema OLTP. Ti suggerisco di guardare il DMV degli indici mancanti e vedere se ci sono indici (quasi sicuri che ce ne saranno più di pochi) che si trovano nei proc discutibili.

http://sqlfool.com/2009/04/a-look-at-missing-indexes/

http://troubleshootingsql.com/2009/12/30/how-to-find-out-the-missing-indexes-on-a-sql-server-2008-or-2005-instance-along-with-the- index-comandi create-/

Cerca anche il post di Jonathan Kehayias su sqlblog.com su questo.

Inoltre, dai un'occhiata allo sniffer dei parametri.

http://sommarskog.se/query-plan-mysteries.html

http://pratchev.blogspot.com/2007/08/parameter-sniffing.html

NON è una risposta competitiva per le tue esigenze ma un buon punto di partenza. Facci sapere se hai bisogno di maggiori dettagli.


1

Abbiamo riscontrato un problema simile dopo che uno dei dipendenti ha riscritto alcune delle procedure memorizzate. Si è scoperto che c'era eccessiva ramificazione e creazione di SQL dinamico che alterava significativamente la clausola where.

Ad esempio (semplificato ovviamente):

Se il modello era "X", la clausola where ha cercato ProductCode equivale a determinati valori.
Se il modello era "Y", la clausola where ha cercato ProductType equivale a determinati valori.

SQL Server costruirà un piano di query basato sui parametri di input la prima volta che viene eseguita la procedura memorizzata. Pertanto, se il piano di query è basato su una logica che utilizza "ProductCode" è uguale e si richiede "ProductType" è uguale a un piano di query non corrispondente e molto probabilmente si traduce in una scansione completa della tabella.

Puoi provare a posizionare " WITH RECOMPILE " nella parte superiore della procedura memorizzata. CREATE PROCEDURE (Transact-SQL)

Il modo migliore per descriverlo è il seguente:

Supponiamo di avere un elenco di nomi e numeri di telefono ordinati per Cognome. Funziona benissimo per trovare persone che usano il loro cognome (piano di query basato sul cognome). Supponiamo ora che tu abbia bisogno di tutti i nomi e i numeri di telefono nel prefisso 203. Se la tua lista è ordinata per Cognome, l'unico modo per ottenere un elenco completo di tutte le persone del prefisso 203 è iniziare dall'alto e leggere in sequenza attraverso ciascuno e ogni record. (Scansione tabella completa).


L'uso della exec()funzione spiegherebbe il comportamento osservato. In questo caso l'uso sp_executesqlnormale risolve i problemi con istruzioni SQL dinamiche.
ajeh

1

Se le query vengono eseguite in modo intermittente veloce e lento in SSMS e nell'app, è possibile che si sia verificato un problema relativo allo sniffing delle statistiche o dei parametri.

Eseguirò queste stored procedure, quindi rivedere il piano di esecuzione per estrarre le proprietà dell'operatore root (nodo verde all'estrema sinistra di ogni istruzione).

Qual è il numero stimato di righe nel piano di esecuzione, rispetto a quante righe effettive sono state restituite?

Il parametro compilato corrisponde al parametro di query effettivo?

Se il piano di esecuzione è stato creato per un parametro che restituisce solo una manciata di righe e si esegue la stessa procedura con un parametro che restituisce un numero elevato di righe, SQL potrebbe utilizzare il piano di esecuzione errato per la query.

Le scelte del piano di esecuzione sono strettamente legate alle statistiche SQL, quindi è una buona idea ricostruire le statistiche su base regolare.

Se si dispone di una procedura memorizzata che a volte restituisce piccole quantità di dati o grandi quantità di dati a seconda del parametro fornito, è possibile che si verifichi un problema di sniffing dei parametri.

Se la ricostruzione delle statistiche non risolve il problema, è possibile eseguire le dichiarazioni più costose nella procedura memorizzata con OPTION (RECOMPILE)


0

Dopo aver identificato query a esecuzione prolungata, è possibile recuperare i piani di esecuzione per queste procedure dalla cache e vedere se è possibile determinare il problema lì. Spesso ci sono conversioni implicite o di runtime di tipi di dati. Inoltre, se si eliminano o si inseriscono molti dati, è consigliabile aggiornare anche le statistiche.

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.