Quindi, in pratica, ho questa stored procedure relativamente lunga. Il flusso di esecuzione di base è che è SELECTS INTO
alcuni dati in tabelle temporanee dichiarate con il segno #
e quindi esegue un cursore attraverso queste tabelle generando un "totale parziale" in una terza tabella temporanea creata utilizzando CREATE
. Quindi questa tabella temporanea risultante viene unita ad altre tabelle nel DB per generare il risultato dopo alcuni raggruppamenti, ecc. Il problema è che questo SP funzionava correttamente fino ad ora restituendo risultati in 1-2 minuti. E ora improvvisamente sta prendendo 12-15 minuti. Se estraggo la query dall'SP e la eseguo nello studio di gestione impostando manualmente gli stessi parametri, restituisce risultati in 1-2 minuti ma l'SP impiega molto tempo. Qualche idea su cosa potrebbe accadere. Ho provato a generare i piani di esecuzione effettiva sia di Query che di SP ma non è stato possibile generarlo a causa del cursore. Qualche idea sul perché l'SP impiega così tanto tempo mentre la query non lo fa?SP richiede 15 minuti ma la stessa query eseguita restituisce 1-2 minuti
risposta
Questo è il footprint del parametro-sniffing. Vedi qui per un'altra discussione a riguardo; SQL poor stored procedure execution plan performance - parameter sniffing
Ci sono diverse correzioni possibili, inclusa l'aggiunta di RECOMPILE alla procedura memorizzata che funziona circa la metà del tempo.
La correzione consigliata per la maggior parte delle situazioni (anche se dipende dalla struttura della query e sProc) è quello di NON utilizzare i parametri direttamente nelle query, ma piuttosto memorizzarli in variabili locali e quindi utilizzare tali variabili nel interrogazioni.
Eeeek !!! Grazie RBarry Young! .. Ho appena modificato il mio proc per utilizzare una variabile locale invece di parametro e il proc è andato da 10 secondi a 0 secondi! –
Ciò si verifica quando una procedura memorizzata differisce ampiamente a seconda di quali parametri vengono passati o quando viene eseguita. Qualche piano di query precedentemente calcolato finisce per essere totalmente sbagliato per la prossima esecuzione. La soluzione migliore è rimuovere queste variazioni dalle stored procedure. Se 'WITH RECOMPILE' sta aiutando, allora non ha senso usare una stored procedure. Esistono per le prestazioni, non per la programmazione strutturata. Se vuoi fare due cose diverse, crea due stored procedure. – Jodrell
@Jodrell Mentre la prima parte del commento è corretta, l'ultima parte non lo è. Le stored procedure servono a diversi scopi in SQL Server e le prestazioni non sono nemmeno le più importanti. – RBarryYoung
Suggerisco che il problema è legato al tipo di tabella temporanea (il prefisso #). Questa tabella temporanea contiene i dati per quella sessione del database. Quando lo esegui attraverso la tua app, la tabella temporanea viene cancellata e ricreata.
È possibile trovare quando si esegue in SSMS che mantiene i dati della sessione e aggiorna la tabella anziché crearla. Spero che questo aiuti :)
Qualche motivo per il downvote? – Russell
Direi che potrebbe essere possibile fino alla cache. Se si esegue la stored procedure due volte è più veloce la seconda volta?
Per ulteriori informazioni è possibile eseguirli sia dallo studio di gestione la stored procedure e la versione di query con l'opzione di piano di query show attivato in studio di gestione, quindi confrontare quale area sta impiegando più tempo nella stored procedure quindi quando viene eseguito come query.
In alternativa è possibile inserire qui la procedura memorizzata affinché le persone suggeriscano le ottimizzazioni.
provare a ricompilare lo sproc fosso qualsiasi piano di query memorizzata
exec sp_recompile 'YourSproc'
quindi eseguire lo sProc avendo cura di utilizzare paramters sensibili.
Confrontare anche i piani di esecuzione effettivi tra i due metodi di esecuzione della query.
Potrebbe anche valere la pena di ricalcolare le statistiche.
Per iniziare, non sembra che SQL stia andando troppo bene in ogni caso in base all'uso di un certo numero di tabelle temporanee (potrebbe essere tenuto in memoria, o persistere in tempdb - qualsiasi cosa decida SQL Server è meglio) e l'uso di cursori.
Il mio suggerimento sarebbe di vedere se è possibile riscrivere lo sproc come una query basata su set invece di un approccio a cursore che offrirà prestazioni migliori e sarà molto più facile da sintonizzare e ottimizzare. Ovviamente non so esattamente cosa fa il tuo sproc, per dare un'indicazione di quanto sia facile/praticabile questo per te.
Per quanto riguarda il motivo per cui la SP impiega più tempo della query - difficile da dire. C'è lo stesso carico sul sistema quando provi ciascun approccio? Se si esegue la query stessa quando c'è un carico leggero, sarà migliore rispetto a quando si esegue l'SP durante un carico pesante.
Inoltre, per garantire che la query sia effettivamente più veloce dell'SP, è necessario escludere la memorizzazione dei dati/del piano di esecuzione che rende più veloce una query per le esecuzioni successive.È possibile svuotare la cache utilizzando:
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
Ma eseguirlo solo su un server di sviluppo/test db, non in produzione. Quindi eseguire la query, registrare le statistiche (ad esempio da profiler). Cancella di nuovo la cache. Esegui il SP e confronta le statistiche.
L'esecuzione di totali è una delle poche volte in cui l'utilizzo di un cursore potrebbe essere più rapido del codice basato su set. – HLGEM
1) Quando si esegue la query per la prima volta, potrebbe essere necessario più tempo. Un altro punto è se si sta utilizzando una subquery corellata e se si stanno codificando i valori verrà eseguito per una sola volta. Quando non lo si sta codificando e lo si esegue attraverso la procedura e se si sta tentando di ricavare il valore dal valore di input, potrebbe essere necessario più tempo.
2) In rari casi può essere dovuto al traffico di rete, anche dove non avremo coerenza nel tempo di esecuzione della query per gli stessi dati di input.
Vorrei anche esaminare lo sniffing dei parametri. Potrebbe essere il proc ha bisogno di gestire i parametri in modo leggermente diverso.
Di solito inizio a risolvere problemi simili usando "print getdate() + '- step'". Questo mi aiuta a restringere ciò che richiede più tempo. È possibile confrontare da dove viene eseguito da Query Analyzer e restringere il punto in cui si trova il problema.
Anche io ho dovuto affrontare un problema in cui dovevamo creare alcune tabelle temporanee e quindi manipolarle dovevano calcolare alcuni valori basati su regole e infine inserire i valori calcolati in una terza tabella. Questo tutto se messo in singola SP stava prendendo circa 20-25 minuti. Quindi per ottimizzarlo ulteriormente abbiamo rotto la sp in 3 diversi sp e il tempo totale ora impiegato era di circa 6-8 minuti. Identifica solo i passaggi coinvolti nell'intero processo e come suddividerli in diversi sp. Sicuramente utilizzando questo approccio il tempo complessivo impiegato dall'intero processo si ridurrà.
è dovuto allo sniffing dei parametri. prima di tutto dichiarare la variabile temporanea e impostare il valore della variabile in entrata sulla variabile temp e utilizzare la variabile temp in tutta l'applicazione, ecco un esempio qui sotto.
ALTER PROCEDURE [dbo].[Sp_GetAllCustomerRecords]
@customerId INT
AS
declare @customerIdTemp INT
set @customerIdTemp = @customerId
BEGIN
SELECT *
FROM Customers e Where
CustomerId = @customerIdTemp
End
provare questo approccio
Il vostro SP dispone di parametri? – RBarryYoung