2011-02-07 11 views
6

Tengo un procedimiento almacenado que hace algo como:Está reemplazando la lógica condicional con sentencias CASE eficientes en Transact-SQL?

IF @Param = '1' 
    SELECT HT.HeaderKey, HT.Description, 
      (SELECT SUM(E1) -- E1 is actually a complex expression 
      FROM DetailTable DT INNER JOIN ... 
            INNER JOIN ... 
            INNER JOIN ... 
      WHERE DT.HeaderKey = HT.HeaderKey) 
    FROM HeaderTable HT 
ELSE IF @Param = '2' 
    SELECT HT.HeaderKey, HT.Description, 
      (SELECT SUM(E2) -- E2 is yet another complex expression 
      FROM DetailTable DT INNER JOIN ... -- Here, DetailTable is not 
            INNER JOIN ... -- joined to the same tables 
            INNER JOIN ... -- as in the first case 
      WHERE DT.HeaderKey = HT.HeaderKey) 
    FROM HeaderTable HT 
-- Etc. There are five cases. 

I gustaría para reducir la consulta a la siguiente:

SELECT HT.HeaderKey, HT.Description, 
     CASE @Param 
     WHEN '1' 
      (SELECT SUM(E1) 
      FROM DetailTable DT INNER JOIN ... 
            INNER JOIN ... 
            INNER JOIN ... 
      WHERE DT.HeaderKey = HT.HeaderKey) 
     WHEN '2' 
      (SELECT SUM(E2) 
      FROM DetailTable DT INNER JOIN ... 
            INNER JOIN ... 
            INNER JOIN ... 
      WHERE DT.HeaderKey = HT.HeaderKey) 
     -- Etc. 
     ELSE 0 
     END 
FROM HeaderTable HT 

Sin embargo, si SQL Server evalúa todos los casos , independientemente de cuál será realmente devuelto, la consulta modificada sería extremadamente ineficiente.

Por lo tanto, me gustaría saber, Cómo evalúa SQL Server todos los casos en un comunicado CASE, o sólo el primero que satisface la condición de la CASE 's?

+0

1 para la buena pregunta –

+0

Gracias, Stephanie. – pyon

Respuesta

2

La sentencia CASE de SQL Server, como se menciona en this article, aprovecha un cortocircuito, por lo que en el ejemplo que se muestra no evaluará los resultados de cada posible resultado de CASE para cada fila.
Sin embargo, igual obtendrá una consulta menos eficiente que su formato actual, ya que forzará a todos los resultados a compartir el mismo plan de ejecución, que puede no ser óptimo. Dependiendo de las diferencias entre las subconsultas CASE, el efecto podría ser bastante significativo.

+0

¿Cómo está forzando su formato actual a que cada consulta comparta el mismo plan? El formato actual tiene consultas separadas. Cada uno tiene alguna diferencia en alguna parte, si no lo hacen entonces ¿por qué el caso? –

+0

Simplemente agregará una ruta diferente en el plan para cada resultado de 'caso'. No hay una razón particular para pensar que un camino adicional hará que otras partes del plan empeoren. –

+0

Está leyendo mi respuesta incorrectamente, dice "todavía obtendrá una consulta menos eficiente que su formato ACTUAL". La segunda parte de OP es su formato propuesto, que es menos eficiente que su formato actual (aunque probablemente sea un poco más fácil de mantener). – MartW

-1

Casi siempre obtendrá un resultado más rápido con una solución basada en conjuntos frente a una solución basada en procedimientos en SQL Server (y todos los RDMS).

+0

Se establece en base. Él pregunta qué "conjunto" será más rápido. –

+0

Si las declaraciones no se establecen en SQL Server. – richard

+0

Correcto, pero después del IF, se ejecutará una instrucción SQL. El "trabajo" se realiza en un SET ... la evaluación de un IF es menos que minúscula en comparación con el sql. Estás llevando una máxima simple al extremo. Decimos que el conjunto basado es mejor, no significa que la primera línea de código elimine el rendimiento. Significa no bucle y procesar tablas fila por fila. –

0

el supuesto de que las uniones son los mismos en cada sub consulta, me gustaría probar algo como esto:

;with dt as 
(
    select 
     HeaderKey, 
     sum(case @Param 
      when 1 then E1 
      when 2 then E2 
      ...) as ExpressionSum 
    from DetailTable DT 
     inner join... 
    group by dt.HeaderKey 
) 
select 
    ht.HeaderKey, 
    ht.description, 
    dt.ExpressionSum 
from HeaderTable HT 
    inner join dt 
     on HT.HeaderKey=dt.HeaderKey 

o podría ser mal entendido groseramente lo que estás tratando de hacer;)

+1

"Aquí, DetailTable no está unido a las mismas tablas que en el primer caso". AVISO el comentario. No son las mismas tablas ... –

+0

@stephanie, no vi eso, gracias – DForck42

+0

Lo extrañé también ... –

Cuestiones relacionadas