Il codice crea un piano diverso quando viene eseguito ad-hoc rispetto a una procedura memorizzata


9

Ho una dichiarazione di eliminazione che utilizza un piano errato quando eseguito all'interno di una procedura memorizzata, ma sta scegliendo un piano molto migliore quando eseguito ad-hoc.

Ho ricostruito tutti gli indici per le tabelle utilizzate dalla query e ho eliminato tutte le cache. L'ottimizzatore sceglie ancora il piano errato per la procedura memorizzata.

Vorrei sapere perché l'ottimizzatore utilizza un piano di esecuzione diverso per la procedura memorizzata rispetto all'SQL ad hoc.

AGGIORNAMENTO: Immagino che dopo tutto debbano essere stati i parametri - quando ho eseguito il codice ad-hoc con la variabile hardcoded, posso ottenere il piano "cattivo" con il giusto valore (è una data, valori vecchi di un anno sembra generare il "buon" piano). Ora proviamo a forzare il piano "buono" sul proc usando un suggerimento per la query.

SOLUZIONE: ho finito per ottenere il piano che volevo usando il suggerimento OTTIMIZZA PER SCONOSCIUTO.


Probabilmente sta annusando i parametri . La query fa riferimento a una variabile nella sua WHEREclausola?
Nick Chammas,

4
Puoi aggiungere il codice per favore
gbn

Pubblica anche i piani da qualche parte per favore. Così com'è, sarà piuttosto difficile dirti esattamente perché i piani sono diversi.
Aaron Bertrand

OK, ulteriori informazioni: non posso pubblicare piani e codici finché non li offendo un po '. Proverò a sollevarli in pochi. Il piano per la procedura memorizzata (non valido) esegue una scansione di indice cluster di una tabella di grandi dimensioni (l'intera cosa, tutte le partizioni). Quindi utilizza un ciclo per trovare le righe da una tabella più piccola, quindi elimina dalla tabella più piccola.
msgisme

Il piano per il codice ad-hoc (buono) esegue una scansione della tabella della tabella piccola (che ha solo 5-10 righe) e utilizza un indice non cluster della tabella grande per trovare le righe da controllare nel PK del grande tavolo. Cercherò di mettere in atto i piani attuali il prima possibile.
msgisme

Risposte:


5

Soliti sospetti:

  1. costanti in ad hoc, parametri nel codice
  2. mancata corrispondenza dei tipi di dati nel codice
  3. fiuto dei parametri

Punto 1: l'ottimizzatore può scegliere il piano migliore per le costanti.
Cambia le costanti = cambia il piano. Un plen parametrizzato è resuable

Il punto 2 introdurrà conversioni implicite a causa della precedenza del tipo di dati,
ad esempio la colonna varchar rispetto al parametro nvarchar

Punto 3: utilizzare il mascheramento dei parametri o OTTIMIZZA PER SCONOSCIUTO
Modifica: per testare: eseguire stored procedure, eseguire sp_updatestats, eseguire nuovamente. Ciò invaliderà i piani memorizzati nella cache, meglio quindi svuotare la cache dei piani

Modifica: dopo il commento di jcolebrand

È possibile disabilitare lo sniffing in diversi modi. I 3 principali sono

  • RECOMPILE. Questo è sciocco IMO.
  • OTTIMIZZARE (sic) PER SCONOSCIUTO
  • Mascheramento dei parametri

Mascheramento dei parametri:

DECLARE @MaskedParam varchar(10)
SELECT @MaskedParam = @SignaureParam

SELECT...WHERE column = @MaskedParam

Il mascheramento e il suggerimento OPTIMIZE hanno lo stesso effetto (forse per motivi diversi). Cioè, l'ottimizzatore deve utilizzare le statistiche e la distribuzione dei dati ( Nota: ancora in fase di test da Mark Storey-Smith ) valutare i parametri in base ai propri meriti ? , piuttosto che quello che erano l'ultima chiamata. L'ottimizzatore può ricompilare o meno. SQL Server 2005 ha aggiunto la ricompilazione a livello di istruzione, quindi l'impatto è stato minore

Ora, perché un piano con parametri "annusati" è "appiccicoso" rispetto ai parametri mascherati / "sconosciuti", non sono sicuro.

Ho usato il mascheramento dei parametri da SQL Server 2000 per tutti tranne il codice più semplice. Ho notato che è probabile che accada con un codice più complesso. E nel mio vecchio lavoro ho alcuni proc di report che potrei cambiare le impostazioni predefinite dei parametri del piano. Ritengo che l'approccio del "culto delle merci" sia stato più semplice di una richiesta di supporto.

Modifica 2, 12 ott 2011, dopo alcune chat

  • Il mascheramento dei parametri e OPTIMIZE FOR UNKNOWN hanno lo stesso effetto, per quanto ne so,
    il suggerimento è più pulito del mascheramento ma è stato aggiunto con SQL Server 2008.

  • Lo sniffing dei parametri avviene al momento della compilazione.
    WITH RECOMPILE genera un nuovo piano ogni esecuzione. Ciò significa che una scelta errata di valori predefiniti influenzerà il piano. Nel mio ultimo lavoro, ho potuto dimostrarlo facilmente con un codice di report: la modifica delle impostazioni predefinite dei parametri ha modificato il piano indipendentemente dai parametri forniti.

  • Questo articolo di MS Connect è interessante: utilizzo dell'indice non ottimale all'interno della procedura memorizzata (menzionato in una delle risposte SO di seguito)

  • Anche Bob Beauchemin lo menziona

Problemi eccezionali

  • Lo sniffing si applica ancora con WITH RECOMPILE? Cioè, se l'ottimizzatore sa scartare il piano, mira a riutilizzarlo?

  • Perché i piani sniffati sono "appiccicosi"?

Collegamenti da SO:


1. Il parametro in sp è una variabile nel codice 2. Ancora una volta, lo stesso tipo di dati 3. Ho eseguito entrambi con un'ampia varietà di parametri e ottengo lo stesso piano ogni volta. Ho cancellato la cache dopo ogni tentativo.
msgisme

1
Ri: punto 3. È inoltre possibile eseguire l'istruzione con OPTION (RECOMPILE)o l'intero proc WITH RECOMPILEper forzare SQL Server a ignorare i piani esistenti.
Nick Chammas,

3
A proposito OPTIMIZE, perché Microsoft è una società americana. :)
Nick Chammas il

1
Hai qualche idea su come prevenire / sconfiggere lo sniffing dei parametri?
jcolebrand

1
@jcolebrand: la risposta semplice è "no" :-)
gbn

2

Non dimenticare che le impostazioni ANSI configurate per il piano di connessione hanno un ruolo nella selezione del piano di esecuzione. Quando l'app chiama la procedura memorizzata, probabilmente ha impostazioni ANSI diverse rispetto alla connessione SSMS.

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.