2008-10-17 11 views
60

Qualche tempo fa ho ricevuto una query che ho eseguito molto per uno dei miei utenti. Si stava ancora evolvendo e ottimizzando, ma alla fine si è stabilizzato e ha funzionato abbastanza velocemente, quindi abbiamo creato una procedura memorizzata da esso.Parametro Sniffing (o Spoofing) in SQL Server

Finora, così normale.

La procedura memorizzata, tuttavia, era cane lento. Nessuna differenza sostanziale tra la query e il proc, ma il cambio di velocità è stato enorme.

[Sfondo, siamo in esecuzione SQL Server 2005.]

Un DBA accogliente locale (che non lavora più qui) ha preso uno sguardo alla stored procedure e ha detto "parametro spoofing!" (Edit: anche se sembra che sia possibilmente anche conosciuto come 'il parametro sniffing', il che potrebbe spiegare la scarsità di Google colpisce quando ho provato a cercare fuori.)

Abbiamo avulse alcune delle stored procedure per un il secondo, avvolse la chiamata a questo nuovo proc interiore in quello esterno preesistente, chiamato quello esterno e, presto, fu veloce come la query originale.

Quindi, cosa dà? Qualcuno può spiegare lo spoofing dei parametri?

credito Bonus per

  • evidenziando come evitarlo
  • suggerendo come riconoscere possibile causa
  • discutere strategie alternative, per esempio statistiche, indici, chiavi, per mitigare la situazione
+0

Non è solo una possibilità, è una certezza - non esiste una cosa come lo spoofing dei parametri. È il parametro che annusa. – ErikE

risposta

52

FYI: è necessario essere a conoscenza di qualcos'altro quando si lavora con SQL 2005 e stored proc con parametri.

SQL Server compilerà il piano di esecuzione del processo memorizzato con il primo parametro utilizzato. Quindi, se esegui questa operazione:

usp_QueryMyDataByState 'Rhode Island' 

Il piano di esecuzione funzionerà al meglio con i dati di un piccolo stato.Ma se qualcuno si gira e corre:

usp_QueryMyDataByState 'Texas' 

Il piano di esecuzione progettato per Rhode-Island dimensioni dei dati potrebbe non essere così efficiente con i dati del Texas-dimensioni. Ciò può produrre risultati sorprendenti quando il server viene riavviato, poiché il piano di esecuzione appena generato verrà indirizzato a qualunque parametro venga utilizzato per primo, non necessariamente il migliore. Il piano non verrà ricompilato fino a quando non ci sarà un grosso motivo per farlo, come se le statistiche venissero ricostruite.

Qui è dove arrivano i piani di query e SQL Server 2008 offre molte nuove funzionalità che aiutano gli amministratori di database a stabilire un piano di query specifico sul posto a lungo termine, indipendentemente dai parametri che vengono richiamati per primi.

La mia preoccupazione è che quando hai ricostruito il tuo proc memorizzato, hai forzato la ricompilazione del piano di esecuzione. L'hai chiamato con il tuo parametro preferito, e poi ovviamente è stato veloce - ma il problema potrebbe non essere stato il proc memorizzato. Potrebbe essere stato che il proc memorizzato è stato ricompilato ad un certo punto con un insieme insolito di parametri e, quindi, un piano di query inefficiente. Potresti non aver corretto nulla e potresti dover affrontare lo stesso problema al successivo riavvio del server o ricompilazione del piano di query.

+2

quindi .... come evitarlo? – thomaspaulb

+3

Raccogli l'eccellente libro di Grant Fritchey SQL Server 2008 Query Performance Distillato in cui esamina tutte le opzioni. Anche se dice il 2008, è ottimo anche per il 2005. –

+0

Raccomando di cercare due soluzioni possibili, la prima che ho provato e visto funzionare, la seconda che sospetto funzionerebbe ma che non ho provato in pratica. –

26

Sì, penso si intenda lo sniffing dei parametri, che è una tecnica utilizzata dall'ottimizzatore di SQL Server per cercare di calcolare i valori/gli intervalli dei parametri in modo che possa scegliere la migliore esecuzione pianificare la tua richiesta. In alcuni casi, SQL Server non funziona correttamente durante lo snifing dei parametri. & non seleziona il piano di esecuzione ottimale per la query.

Credo che questo articolo del blog http://blogs.msdn.com/queryoptteam/archive/2006/03/31/565991.aspx abbia una buona spiegazione.

Sembra che il DBA nell'esempio abbia scelto l'opzione # 4 per spostare la query su un altro sproc in un contesto procedurale separato.

Si potrebbe avere utilizzato anche il con ricompilazione sul sproc originale o usato il Ottimizza per opzione sul parametro.

+1

+1, ma si noti che il "con ricompilazione" potrebbe avere problemi di prestazioni di per sé. Tendo a provare prima l'opzione # 4 ... –

+0

La mia comprensione dei join è il tipo di join (unione/hash/loop) scelta in base a due fattori principali, 1) indici sulle colonne unite 2) statistiche che prevedono la dimensione del join. Pertanto, ogni volta che si esegue la query, in base alla dimensione stimata del join, sceglie il join appropriato. La selezione del join è inserita in una query compilata? Cioè se il parametro sniffing predice in modo scadente la dimensione tipica dei join, verrà inserito nel piano di query il tipo di join scarsamente scelto? – AaronLS

24

Un modo semplice per accelerare è riassegnare i parametri di input ai parametri locali all'inizio dello sproc, ad es.

CREATE PROCEDURE uspParameterSniffingAvoidance 
    @SniffedFormalParameter int 
AS 
BEGIN 

    DECLARE @SniffAvoidingLocalParameter int 
    SET @SniffAvoidingLocalParameter = @SniffedFormalParameter 

    --Work w/ @SniffAvoidingLocalParameter in sproc body 
    -- ... 
+1

Questa soluzione ha ridotto del 50% il tempo di esecuzione della mia interrogazione. Non perfetto ma migliore! –

+0

Ma perché questo aiuta comunque? –

+1

@ TimBüthe: Funziona impedendo a SQL Server di memorizzare nella cache (o utilizzare una versione cache di) un piano di query per la propria procedura. A seconda del valore del parametro, un piano di esecuzione di query potrebbe essere più veloce o più lento di un altro. La prima volta che viene eseguita la procedura, verrà creato un piano basato sul valore del primo parametro. Riassegnandolo localmente, SQL Server utilizzerà ogni volta un nuovo piano. –

4

Lo sniffing dei parametri è una tecnica utilizzata da SQL Server per ottimizzare il piano di esecuzione della query per una stored procedure. Quando si chiama la stored procedure per la prima volta, SQL Server analizza i valori dei parametri forniti dalla chiamata e decide quali indici utilizzare in base ai valori dei parametri.

Pertanto, quando la prima chiamata contiene parametri non tipici, SQL Server potrebbe selezionare e memorizzare un piano di esecuzione non ottimale in relazione alle seguenti chiamate della stored procedure.

È possibile aggirare il problema sia

  • utilizzando WITH RECOMPILE
  • copiare i valori dei parametri per le variabili locali all'interno della stored procedure e utilizzando i locali nelle query.

Ho anche sentito che è meglio non utilizzare le stored procedure a tutti, ma per inviare le vostre domande direttamente al server. Recentemente ho riscontrato lo stesso problema in cui non ho ancora una soluzione reale. Per alcune query, la copia su vars locali consente di tornare al piano di esecuzione corretto, poiché alcune query si degradano con le vars locali.

Devo ancora fare ulteriori ricerche su come SQL Server memorizza nella cache e riutilizza piani di esecuzione (sub-ottimali).

4

Nella mia esperienza, la soluzione migliore per lo sniffing dei parametri è 'SQL dinamico'. Due cose importanti da notare è che 1. dovresti usare i parametri nella tua query sql dinamica 2. dovresti usare sp_executesql (e non sp_execute), che salva il piano di esecuzione per ogni valore di parametro

+0

In un mondo di SQL Attacchi di iniezione, non credo che raccomandare l'SQL dinamico sia una buona idea. – datagod

+1

Ha anche raccomandato l'uso dei parametri, ovvero come evitare l'iniezione SQL. –

-2

Cambiare la procedura di archiviazione da eseguire come un lotto dovrebbe aumentare la velocità.

di file batch selezionare cioè .:

exec ('select * from order where order id ='''+ @ordersID') 

Invece di stored procedure normale selezionare:

select * from order where order id = @ordersID 

Basta passare il parametro come nvarchar e si dovrebbe ottenere risultati più rapidi.

0

Ho avuto un problema simile. Il piano di esecuzione della mia stored procedure è durato 30-40 secondi. Ho provato a utilizzare le dichiarazioni SP nella finestra di query e sono bastati pochi ms per eseguire lo stesso. Poi ho elaborato dichiarando le variabili locali all'interno della stored procedure e trasferendo i valori dei parametri alle variabili locali. Ciò ha reso l'esecuzione SP molto veloce e ora lo stesso SP viene eseguito entro pochi millisecondi anziché 30-40 secondi.

-1

Molto semplice e ordinato, l'ottimizzatore di query utilizza il vecchio piano di query per le query frequenti. ma in realtà anche la dimensione dei dati sta aumentando, quindi in quel momento è necessario un nuovo piano ottimizzato e si sta ancora ottimizzando le query utilizzando il vecchio piano di query. Questo è chiamato Parameter Sniffing. Ho anche creato un post dettagliato su questo. Si prega di visitare questo URL: http://www.dbrnd.com/2015/05/sql-server-parameter-sniffing/