L'indice SEEK non viene utilizzato se non OPTION (RECOMPILE)?


11

(Domanda spostata da SO)

Ho una tabella (dati fittizi) con indice cluster contenente 2 colonne:

inserisci qui la descrizione dell'immagine

Ora eseguo queste due query:

declare 
@productid int =1 , 
@priceid  int = 1




SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid OR @productid IS NULL)
       AND (priceid = @priceid OR @priceid IS NULL)  


SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid)
       AND (priceid = @priceid)

Il piano di esecuzione effettivo per entrambe le query è:

inserisci qui la descrizione dell'immagine

Come puoi vedere, il primo utilizza SCAN mentre il secondo utilizza SEEK.

Tuttavia - aggiungendo OPTION (RECOMPILE)alla prima query, il piano di esecuzione ha reso anche l'uso di SEEK:

inserisci qui la descrizione dell'immagine

Gli amici della chat DBA mi hanno detto che:

Nella tua query, @ productid = 1, il che significa che (productID = @ productID OR @productID IS NULL) può essere semplificato in (productID = @ productID). Il primo richiede una scansione per funzionare con qualsiasi valore di @productID, il secondo potrebbe utilizzare una ricerca. Pertanto, quando si utilizza RECOMPILE, SQL Server esaminerà il valore effettivamente presente in @productID e farà il piano migliore per esso. Con un valore non nullo in @productID, una ricerca è la migliore. Se il valore di @productID è sconosciuto, il piano deve adattarsi a qualsiasi valore possibile in @productID, che richiederebbe una scansione. Attenzione: OPTION (RECOMPILE) imporrà una ricompilazione del piano ogni volta che lo esegui, il che aggiungerà qualche millisecondo a ogni esecuzione. Anche se questo è un problema solo se la query viene eseguita molto frequentemente.

Anche :

Se @productID è null, a quale valore vorresti cercare? Risposta: non c'è niente da cercare. Tutti i valori si qualificano.

Capisco che OPTION (RECOMPILE)costringe SQL Server a vedere quali valori effettivi hanno i parametri e vedere se riesce a SEEK con esso.

Ma ora perdo il vantaggio della compilazione anticipata.

Domanda

IMHO - SCAN si verificherà solo se un parametro è nullo.
Va bene: lascia che SQL SERVER crei un piano di esecuzione per SCAN.
MA se SQL Server vede che eseguo questa query molte volte con valori 1,1:, allora perché non crea UN ALTRO piano di esecuzione e non utilizza SEEK per questo?

AFAIK - SQL crea un piano di esecuzione per le query più colpite .

  • Perché SQL SERVER non salva un piano di esecuzione per:

    @productid int =1 , @priceid int = 1

(Lo eseguo molte volte con quei valori)

  • È possibile forzare SQL a mantenere quel piano di esecuzione (che utilizza SEEK) - per invocazioni future?

Script di tabella + dati di creazione completa


Risposte:


10

Riassumendo alcuni dei punti principali della discussione nella nostra chat room :


In generale, SQL Server memorizza nella cache un unico piano per ogni istruzione . Tale piano deve essere valido per tutti i possibili valori dei parametri futuri .

Non è possibile memorizzare nella cache un piano di ricerca per la query, poiché tale piano non sarebbe valido se, ad esempio, @productid è null.

In alcune versioni future, SQL Server potrebbe supportare un unico piano che sceglie dinamicamente tra una scansione e una ricerca, a seconda dei valori dei parametri di runtime, ma non è qualcosa che abbiamo oggi.

Classe di problema generale

La query è un esempio di un modello variamente definito come query "catch all" o "ricerca dinamica". Esistono varie soluzioni, ognuna con i propri vantaggi e svantaggi. Nelle versioni moderne di SQL Server (2008+), le opzioni principali sono:

  • IF blocchi
  • OPTION (RECOMPILE)
  • SQL dinamico utilizzando sp_executesql

Il lavoro più completo sull'argomento è probabilmente di Erland Sommarskog, che è incluso nei riferimenti alla fine di questa risposta. Non è possibile allontanarsi dalle complessità coinvolte, quindi è necessario investire un po 'di tempo nel provare ciascuna opzione per comprendere i compromessi in ciascun caso.

IF blocchi

Per illustrare una IFsoluzione a blocchi per il caso specifico nella domanda:

IF @productid IS NOT NULL AND @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid
        AND T.priceID = @priceid;
END;
ELSE IF @productid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid;
END;
ELSE IF @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.priceID = @priceid;
END;
ELSE
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T;
END;

Questo contiene un'istruzione separata per i quattro possibili casi null-or-not-null per ciascuno dei due parametri (o variabili locali), quindi esistono quattro piani.

C'è un potenziale problema lì con lo sniffing dei parametri, che potrebbe richiedere un OPTIMIZE FORsuggerimento su ogni query. Si prega di consultare la sezione riferimenti per esplorare questi tipi di sottigliezze.

Riconversione

Come notato sopra e nella domanda, puoi anche aggiungere un OPTION (RECOMPILE)suggerimento per ottenere un nuovo piano (cercare o scansionare) su ogni invocazione. Data la frequenza relativamente lenta delle chiamate nel tuo caso (una volta ogni dieci secondi in media, con un tempo di compilazione inferiore al millisecondo) sembra probabile che questa opzione sia adatta a te:

SELECT
    T.productID,
    T.priceID
FROM dbo.Transactions AS T
WHERE
    (T.productID = @productid OR @productid IS NULL)
    AND (T.priceID = @priceid OR @priceid IS NULL)
OPTION (RECOMPILE);

È anche possibile combinare le funzionalità delle opzioni sopra in modo creativo, per sfruttare al massimo i vantaggi di ciascun metodo, riducendo al minimo gli aspetti negativi. Non c'è davvero alcuna scorciatoia per comprendere queste cose in dettaglio, quindi fare una scelta informata supportata da test realistici.

Ulteriori letture

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.