2010-08-25 17 views
5

Sto sviluppando un sistema che periodicamente (4-5 volte al giorno) esegue un'istruzione select, che normalmente richiede meno di 10 secondi ma che richiede periodicamente fino a 40 minuti.Intermittente query lenta su SQL Server 2008

Il database è su Windows Server 2008 + SQL Server 2008 R2; entrambi a 64 bit.

Esiste un servizio sulla macchina che esegue il database che esegue il polling del database e genera valori per i record che lo richiedono. Questi record vengono quindi interrogati periodicamente utilizzando un join multi tabella selezionato da un servizio su una seconda macchina scritta in C++ (VS 2010) utilizzando la classe MFC CRecordset per estrarre i dati. Di seguito è riportato un esempio della query che causa il problema.

SELECT DISTINCT "JobKeysFrom"."Key" AS "KeyFrom","KeysFrom"."ID" AS "IDFrom", 
"KeysFrom"."X" AS "XFrom","KeysFrom"."Y" AS "YFrom","JobKeysTo"."Key" AS "KeyTo", 
"KeysTo"."ID" AS "IDTo","KeysTo"."X" AS "XTo","KeysTo"."Y" AS "YTo", 
"Matrix"."TimeInSeconds","Matrix"."DistanceInMetres","Matrix"."Calculated" 
FROM "JobKeys" AS "JobKeysFrom" 
INNER JOIN "JobKeys" AS "JobKeysTo" ON 
("JobKeysFrom"."Key"<>"JobKeysTo"."Key") AND 
("JobKeysFrom"."JobID"=531) AND 
("JobKeysTo"."JobID"=531) 
INNER JOIN "Keys" AS "KeysFrom" ON 
("JobKeysFrom"."Key"="KeysFrom"."Key") AND ("JobKeysFrom"."Status"=4) 
INNER JOIN "Keys" AS "KeysTo" ON 
("JobKeysTo"."Key"="KeysTo"."Key") AND ("JobKeysTo"."Status"=4) 
INNER JOIN "Matrix" AS "Matrix" ON 
("Matrix"."IDFrom"="KeysFrom"."ID") AND ("Matrix"."IDTo"="KeysTo"."ID") 
ORDER BY "JobKeysFrom"."Key","JobKeysTo"."Key" 

Ho provato quanto segue

  1. controllato gli indici e tutti sembrano corretti e sono attivi e vengono utilizzati in base alla query
  2. il consulente di design torna con nessun suggerimento
  3. Ho provato a deframmentare gli indici ei dati
  4. ha ricostruito il database da zero esportando i dati e reimportandoli in un nuovo database.
  5. ha eseguito il profiler su di esso e ha scoperto che quando va storto sembra fare molti milioni (fino a 100 milioni) di letture piuttosto che poche centinaia di migliaia.
  6. correva il database su un server diverso

Durante il tempo è in esecuzione della query, posso correre esattamente la stessa query nella finestra di gestione dello studio e sarà di nuovo a correre in 10 secondi. Il problema non sembra essere il blocco, il deadlock, la CPU, il disco o la memoria correlati come è stato fatto quando la macchina che esegue il database stava eseguendo solo questa query. Il server ha 4 processori e 16 GB di memoria per eseguirlo. Ho anche provato ad aggiornare i dischi a quelli molto più veloci e questo non ha avuto alcun effetto.

Mi sembra che sia quasi come se il database riceve la query, inizia a elaborarlo e quindi va a dormire per 40 minuti o esegue la query senza utilizzare gli indici.

Quando impiega molto tempo, alla fine termina e invia i risultati della query (normalmente circa 70-100000 record) all'applicazione chiamante.

Qualsiasi aiuto o suggerimento sarebbe ben accetto, molte grazie

+0

Questa query viene eseguita come una stored procedure con parametri? –

+0

È possibile evitare il SELECT DISTINCT? Questo può danneggiare le prestazioni in modo pesante. –

+1

@Yves: sembra che sia abbastanza performante da eseguire adhoc e ritorna in 10 secondi. –

risposta

3

questo suona molto come parametro di sniffing.

Quando una procedura memorizzata viene richiamata e non esiste alcun piano di esecuzione nella cache corrispondente alle opzioni set per la connessione, un nuovo piano di esecuzione verrà compilato utilizzando i valori dei parametri passati in tale chiamata.

A volte ciò accade quando i parametri passati sono atipici (ad esempio hanno una selettività insolitamente elevata), quindi il piano generato non sarà adatto per la maggior parte delle altre chiamate con parametri diversi. Ad esempio, può scegliere un piano con ricerche di indici e ricerche di segnalibri che va bene per un caso altamente selettivo ma povero se deve essere fatto centinaia di migliaia di volte.

Questo spiegherebbe perché il numero di letture passa attraverso il tetto.

La connessione SSMS probabilmente avrà diverse SET ... opzioni in modo da non otterrà consegnato lo stesso piano problematico dalla cache quando si esegue la stored procedure all'interno SSMS

È possibile utilizzare il seguente per ottenere il piano per la sessione lenta

select p.query_plan, * 
from sys.dm_exec_requests r 
cross apply sys.dm_exec_query_plan(r.plan_handle) p 
where r.session_id = <session_id> 

Quindi confrontare con il piano per la buona sessione.

Se si determina che lo sniffing dei parametri è errato, è possibile utilizzare i suggerimenti OPTIMIZE FOR per evitare che scelga il piano errato.

+0

Penso che costruiamo i nostri discorsi sulle condizioni iniziali e le dichiarazioni non valide :) – garik

0

Verificare che non sia in esecuzione un'attività di manutenzione che sta ricostruendo gli indici o che le statistiche del database non sono valide in qualche modo quando viene eseguita la query.

Questo è esattamente il tipo di cosa che ci si aspetterebbe di vedere se la query non utilizza gli indici, che di solito è perché gli indici non sono accessibili alla query nel momento in cui viene eseguito o perché le statistiche non sono valide e fai in modo che l'ottimizzatore ritenga che le tue tabelle di grandi dimensioni contengano solo poche righe e la query verrà eseguita più rapidamente con una scansione completa della tabella rispetto all'utilizzo dell'accesso indicizzato.

+0

Hai perso il punto che un'esecuzione concorrente della stessa query ritorna rapidamente? –

Problemi correlati