2009-10-08 8 views
16

He estado batallando con este por un tiempo. Tengo un proceso almacenado que toma en 3 parámetros que se utilizan para filtrar. Si se transfiere un valor específico, quiero filtrarlo. Si se pasa -1, dame todo.T-SQL Donde Cláusula Case Statement Optimization (parámetros opcionales para StoredProc)

lo he probado las dos formas siguientes:

Primera forma:

SELECT field1, field2...etc 
FROM my_view 
WHERE 
parm1 = CASE WHEN @PARM1= -1 THEN parm1 ELSE @PARM1 END 
AND parm2 = CASE WHEN @PARM2 = -1 THEN parm2 ELSE @PARM2 END 
AND parm3 = CASE WHEN @PARM3 = -1 THEN parm3 ELSE @PARM3 END 

segunda manera:

SELECT field1, field2...etc 
FROM my_view 
WHERE 
(@PARM1 = -1 OR parm1 = @PARM1) 
AND (@PARM2 = -1 OR parm2 = @PARM2) 
AND (@PARM3 = -1 OR parm3 = @PARM3) 

leí en alguna parte que la segunda manera lo hará corto circuito y nunca evalúa la segunda parte si es verdadero. Mi DBA dijo que obliga a una exploración de tabla. No he verificado esto, pero parece ser más lento en algunos casos.

La tabla principal desde la que se selecciona esta vista tiene alrededor de 1,5 millones de registros, y la vista procede a unirse a otras 15 tablas para recopilar mucha otra información.

Ambos métodos son lentos ... llevándome de 2 segundos a 40 segundos, lo que en mi situación es completamente inaceptable.

¿Existe una forma mejor que no implique dividirla en cada caso específico de vs específico?

Cualquier ayuda es apreciada. Gracias.

Respuesta

6

Leí en alguna parte que la segunda forma se cortocircuitará y nunca evaluará la segunda parte si es verdadera. Mi DBA dijo que obliga a una exploración de tabla.

Has leído mal; será no cortocircuito. Su DBA es correcto; no funcionará bien con el optimizador de consultas y probablemente forzará un escaneo de tabla.

La primera opción es casi tan buena como se pone. Sus opciones para mejorar las cosas son sql dinámico o un largo procedimiento almacenado con cada combinación posible de columnas de filtro para que pueda obtener planes de consulta independientes. También puede intentar usar la opción "CON RECOMPIBLE", pero no creo que lo ayude.

+0

Maldición. Pásame a eso. +1 :) – DVK

+1

La primera opción no necesariamente arrojará los mismos resultados que la segunda. Si tiene filas en su tabla con valores NULL, NO serán devueltas por la consulta de "opción 1". Por ejemplo ... Seleccione * De la tabla donde NullableColumn = NullableColumn –

+0

Los tres parms NO son NULL, por lo que no es un problema en este caso. Parece que podría estar atascado con la opción 1. – IronicMuffin

0

No hay otra forma que se me ocurre luego haciendo:

DONDE

(myCASE es nulo o myCASE = @MyCaseParameter) Y ....

La segunda es más simple y más legible para los desarrolladores si me preguntas.

+1

También es lento como melaza. No lo uses –

+0

@Joel ¿tiene algo que respalde? No es que dude, solo estoy buscando datos duros de una manera u otra. – Jonas

+0

Tengo dos indicadores de que el segundo método puede obligar a una exploración de tabla, y eso no es bueno con 1,5 millones de registros. – IronicMuffin

2

Si pasa de un valor nulo cuando se quiere todo, entonces usted puede escribir su cláusula donde como

Where colName = IsNull(@Paramater, ColName) 

Esto es básicamente igual que el primer método ... que va a funcionar, siempre y cuando la columna en sí no puede contener nulos ... valores nulos IN la columna lo estropeará un poco.

El único método para acelerarlo es agregar un índice en la columna filtrada en la cláusula Where. ¿Ya hay uno?Si no, eso resultará en una mejora dramática.

+0

¿Crees que esto lo acelerará? Parece que básicamente es la misma operación pero verificando null en lugar de -1. IsNull es más eficiente que un CASE? – IronicMuffin

+0

@IronicMuffin, (me gusta tu apodo) No, tienes razón, esto es equivalente al primer método ... –

5

si está ejecutando SQL Server 2005 o superior, puede usar IF para realizar una versión múltiple de la consulta con el WHERE adecuado para que se pueda usar un índice. Cada plan de consulta se colocará en el caché de consultas.

también, aquí es un artículo muy completo sobre este tema:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

que cubre todos los temas y métodos de tratar de escribir consultas con varias condiciones de búsqueda opcionales

aquí está la tabla de contenido:

 
    Introduction 
     The Case Study: Searching Orders 
     The Northgale Database 
    Dynamic SQL 
     Introduction 
     Using sp_executesql 
     Using the CLR 
     Using EXEC() 
     When Caching Is Not Really What You Want 
    Static SQL 
     Introduction 
     x = @x OR @x IS NULL 
     Using IF statements 
     Umachandar's Bag of Tricks 
     Using Temp Tables 
     x = @x AND @x IS NOT NULL 
     Handling Complex Conditions 
    Hybrid Solutions – Using both Static and Dynamic SQL 
     Using Views 
     Using Inline Table Functions 
    Conclusion 
    Feedback and Acknowledgements 
    Revision History
+0

+1 para vincular cualquier cosa por el Sr. Sommarskog –

+0

marcado ... gracias. Utilizamos una combinación de servidores 2000/2005, desafortunadamente este es 2000. – IronicMuffin

+0

El artículo cubre numerosas formas de manejar las condiciones de búsqueda de variables, el IF es solo uno –

0

SQL 2008 y posteriores hacen algunas mejoras a la optimización para cosas como (MyCase IS NULL OR MyCase = @MyCaseParameter) AND ....

Si puede actualizar, y si agrega un OPTION (RECOMPILE) para obtener un rendimiento aceptable para todas las combinaciones de param posibles (esta es una situación en la que no existe un solo plan que sea válido para todas las combinaciones de param posibles), puede encontrar que esto funciona bien

http://blogs.msdn.com/b/bartd/archive/2009/05/03/sometimes-the-simplest-solution-isn-t-the-best-solution-the-all-in-one-search-query.aspx