¿Hay alguna manera de hacer una verificación nula de una variable en una cláusula WHERE que solo se produce una vez?

12

Tengo una consulta en una tabla grande que se ve así:

declare @myIdParam int = 1

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

Hay varios condicionales similares como este en la cláusula where, y también hay muchas uniones, pero este es un resumen.

Efectivamente, si @myIdParam es nulo, no queremos restringir los resultados usando este parámetro.

No soy un DB pro, pero de mis pruebas parece que esta verificación NULL se realiza para cada registro y no se optimiza de ninguna manera.

Si elimino la comprobación nula y asumo que el parámetro no es nulo, la consulta vuelve instantáneamente. De lo contrario, demora hasta diez segundos.

¿Hay alguna manera de optimizar esto para que la verificación se realice solo una vez en tiempo de ejecución?

Mystagogue
fuente
1
Mire esta respuesta: stackoverflow.com/questions/3415582/… tl; dr useOPTION(RECOMPILE)
vercelli
@vercelli esto hace el truco. Teniendo en cuenta que esta pregunta se trata realmente de parámetros opcionales, diría que es un duplicado del que vinculó.
Mystagogue
Probablemente, pero es una publicación de hace 6 años. Quizás con SqlServer 2014 o 2016 haya un nuevo enfoque. (Lo probé en 2014 sin recompilar y me llevó una eternidad)
vercelli
Dado que su consulta real tiene muchos parámetros opcionales, el SQL dinámico proporcionará el mejor rendimiento. Ver sommarskog.se/dyn-search.html para un artículo completo sobre el tema.
Dan Guzman
@DanGuzman usando WITH RECOMPILE como se describe en la pregunta vercelli enlazada redujo el tiempo de consulta de poco menos de un minuto a prácticamente instantáneo con criterios altamente selectivos. Considero que esta es la mejor opción para equilibrar el rendimiento y la legibilidad.
Mystagogue

Respuestas:

8

Una forma es usar SQL dinámico, usando una verificación nula para agregar opcionalmente esa parte de la cláusula 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
Mystagogue
fuente
2
Realmente preferiría no hacer esto, pero es una solución. Mi esperanza es que alguien venga con uno mucho mejor.
Mystagogue
1
Esta es la mejor manera de manejar esta clase de consulta de búsqueda. La respuesta de stackoverflow mencionada por @vercelli contiene excelentes referencias sobre cómo hacer esto.
Max Vernon
Este es el mejor método, pero noté que falta el parámetro @params para sp_ExecuteSQLy el @vc_dynamicsqlparámetro debe ser a NVARCHAR.
James Anderson el
4

Cada vez que coloca una función alrededor de una columna `ISNULL (@var, table.col) ', por ejemplo, elimina la capacidad de SQL para usar un índice. Esta es realmente la mejor opción si desea mantenerla en una sola consulta.

@var IS NULL or @var = table.col

De lo contrario, tienes dos opciones. El primero es SQL dinámico y la respuesta de @ Mystagogue es suficiente para eso, de lo contrario, puede realizar dos consultas como esta:

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

Tanto en este formato como en el SQL dinámico, obtendrá un plan de consulta diferente para cada una de las consultas (lo que potencialmente generará un mejor rendimiento).

Kenneth Fisher
fuente
El Sql en la pregunta no está usando ISNULL ni ninguna otra función.
Mystagogue
@ MystagogueI Estaba haciendo referencia a una respuesta ahora eliminada.
Kenneth Fisher
0

Bien tu puedes:

declare @myIdParam int = 1;

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

Tenga en cuenta, sin embargo, que la nullif()función es esencialmente una envoltura case. No es una bala de plata que elimina mágicamente ORy, por lo tanto, acelera la consulta.

Roger Wolf
fuente
el uso de funciones en una cláusula where tiene un impacto negativo en el rendimiento porque impide el uso de índices (o eso he oído)
Mystagogue
@Mystagogue, sí, por lo general, las condiciones de búsqueda no son SARGable. Por desgracia, esta es la única forma en que sé cómo responder a su pregunta sin recurrir a SQL dinámico o múltiples correos UNIONelectrónicos. Cuando tuve esta tarea exacta, elegí SQL dinámico.
Roger Wolf