2011-02-07 9 views
6

Ho una stored procedure che fa qualcosa di simile:Sostituisce la logica condizionale con le istruzioni CASE efficienti in 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. 

mi piacerebbe per ridurre la query al seguente:

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 

Tuttavia, se SQL Server valuta tutti i casi , indipendentemente da quale verrà effettivamente restituito, la query modificata sarebbe gravemente inefficiente.

Così, mi piacerebbe sapere, non SQL Server valutare tutti i casi in una dichiarazione CASE, oppure solo il primo che soddisfa la condizione s' il CASE?

+0

+1 per la bella domanda –

+0

Grazie, Stephanie. – pyon

risposta

2

La dichiarazione CASE di SQL Server, come menzionato in this article, sfrutta il cortocircuito, pertanto nell'esempio illustrato non valuterà i risultati di tutti i possibili risultati CASE per ogni riga.
Tuttavia, si otterrà comunque una query meno efficiente rispetto al formato corrente, in quanto si dovranno quindi forzare tutti i risultati a condividere lo stesso piano di esecuzione, che potrebbe non essere ottimale. A seconda delle differenze tra le subquery CASE, l'effetto potrebbe essere piuttosto significativo.

+0

In che modo il suo formato corrente obbliga ogni query a condividere lo stesso piano? Il formato corrente ha query separate. Ognuno ha qualche differenza da qualche parte, se non lo fanno allora perché il caso? –

+0

Aggiungerà semplicemente un percorso diverso nel piano per ogni risultato 'caso'. Non vi è alcun motivo particolare per pensare che un percorso aggiuntivo causerà il peggioramento di altre parti del piano. –

+0

Stai leggendo la mia risposta errata - dice "otterrà comunque una query meno efficiente del tuo formato CORRENTE". La seconda parte dell'OP è il loro formato proposto, che è meno efficiente del loro formato attuale (anche se probabilmente è un po 'più facile da mantenere). – MartW

-1

Quasi sempre si ottiene un risultato più veloce con una soluzione basata su set rispetto a una soluzione basata su procedure in SQL Server (e tutti gli RDMS).

+0

È impostato in base. Chiede quale "set" sarà più veloce. –

+0

Se le istruzioni non sono impostate in base a SQL Server. – richard

+0

Giusto, ma dopo l'IF, verrà eseguita un'istruzione SQL. Il "lavoro" viene fatto in un SET ... la valutazione di un IF è inferiore a minuscola rispetto al sql. Stai portando una semplice massima ad un estremo. Diciamo che il set basato è migliore, non significa che la primissima linea di codice uccide le prestazioni. Significa non eseguire il ciclo ed elaborare le tabelle riga per riga. –

0

assumendo che la unisce sono gli stessi in ogni sottoquery, mi piacerebbe provare qualcosa di simile:

;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 potrei essere malinteso grossolanamente quello che stai cercando di fare;)

+1

"Qui, DetailTable non è unito alle stesse tabelle come nel primo caso." AVVISO il commento. Non sono gli stessi tavoli ... –

+0

@stephanie, non l'ho visto, grazie – DForck42

+0

Anche questo l'ho perso ... –

Problemi correlati