Esiste un modo per effettuare un controllo null su una variabile in una clausola WHERE solo una volta?


12

Ho una query su un grande tavolo che assomiglia a questo:

declare @myIdParam int = 1

select * 
from myTable
where (@myIdParam is null or myTable.Id = @myIdParam)

Esistono diversi condizionali simili come questo nella clausola where e ci sono anche molti join, ma questo è un riepilogo.

In effetti, se @myIdParam è null, non vogliamo limitare i risultati utilizzando questo parametro.

Non sono un professionista del DB, ma dai miei test sembra che questo controllo NULL venga eseguito per ogni record e non ottimizzato in alcun modo.

Se rimuovo il controllo null e presumo che il parametro non sia null, la query ritorna immediatamente. Altrimenti, ci vogliono fino a dieci secondi.

C'è un modo per ottimizzare ciò in modo che il controllo venga eseguito solo una volta in fase di esecuzione?


1
Guarda questa risposta: stackoverflow.com/questions/3415582/… tl; dr useOPTION(RECOMPILE)
vercelli

@vercelli questo fa il trucco. Considerando che questa domanda riguarda davvero i parametri opzionali, direi che è un duplicato di quello che hai collegato.
Mystagogue,

Probabilmente, ma è un post di 6 anni fa. Forse con SqlServer 2014 o 2016 c'è un nuovo approccio. (L'ho provato nel 2014 senza ricompilare e ho impiegato un'eternità)
vercelli,

Poiché la tua query effettiva ha molti parametri opzionali, SQL dinamico fornirà le migliori prestazioni. Vedi sommarskog.se/dyn-search.html per un approfondito articolo sull'argomento.
Dan Guzman,

@DanGuzman utilizzando WITH RECOMPILE come indicato nella domanda collegata vercelli ha ridotto il tempo di interrogazione da poco meno di un minuto a praticamente istantaneo con criteri altamente selettivi. Considero questa la migliore opzione per bilanciare prestazioni e leggibilità.
Mystagogue,

Risposte:


8

Un modo consiste nell'utilizzare SQL dinamico, usando un controllo null per aggiungere facoltativamente quella parte della clausola where.

declare @myIdParam int = 1
declare @vc_dynamicsql varchar(max)

set @vc_dynamicsql = 'select * from myTable where 1=1'

if @myIdParam is not null
    set @vc_dynamicsql = @vc_dynamicsql + ' and  myTable.Id = @myIdParam'

EXECUTE sp_executesql @vc_dynamicsql

2
Preferirei davvero non farlo, ma è una soluzione. La mia speranza è che qualcuno arrivi con uno molto migliore.
Mystagogue,

1
Questo è il modo migliore per gestire questa classe di query di ricerca. La risposta stackoverflow a cui fa riferimento @vercelli contiene ottimi riferimenti su come eseguire questa operazione.
Max Vernon,

Questo è il metodo migliore ma ho notato che manca il parametro @params per sp_ExecuteSQLe che il @vc_dynamicsqlparametro deve essere a NVARCHAR.
James Anderson,

4

Ogni volta che si inserisce una funzione attorno a una colonna "ISNULL (@var, table.col)", ad esempio, si rimuove la capacità di SQL di utilizzare un indice. Questa è davvero l'opzione con le migliori prestazioni se si desidera mantenerla in una singola query.

@var IS NULL or @var = table.col

Altrimenti hai due opzioni. Il primo è SQL dinamico e la risposta di @ Mystagogue è sufficiente, altrimenti puoi inserire due query come questa:

IF @var is NULL
     SELECT * FROM table
ELSE
     SELECT * FROM table WHERE @var = col

In questo formato e nell'SQL dinamico otterrai effettivamente un piano di query diverso per ciascuna query (che potenzialmente produrrà prestazioni migliori).


Il SQL nella domanda non utilizza ISNULL o qualsiasi altra funzione.
Mystagogue,

@Mystagogue: mi riferivo a una risposta ora cancellata.
Kenneth Fisher,

0

Bene, puoi:

declare @myIdParam int = 1;

select *
from myTable
where nullif(@myIdParam, myTable.Id) is null;

Tieni presente, tuttavia, che la nullif()funzione è essenzialmente un wrapper case. Non è un proiettile d'argento che elimina magicamente ORe quindi accelera la query.


l'uso delle funzioni in una clausola where ha un impatto negativo sulle prestazioni perché impedisce l'uso degli indici (o almeno così ho sentito)
Mystagogue

@Mystagogue, sì - di solito rende le condizioni di ricerca non SARGable. Ahimè, questo è l'unico modo in cui so come rispondere alla tua domanda senza ricorrere a SQL dinamico o multipli UNION. Quando ho avuto questo preciso compito, ho scelto SQL dinamico.
Roger Wolf,
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.