Эффективна ли замена условной логики операторами CASE в Transact-SQL? - PullRequest
6 голосов
/ 07 февраля 2011

У меня есть хранимая процедура, которая выполняет что-то вроде:

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.

Я хотел бы сократить запрос до следующего:

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

Однако,если SQL Server оценивает все случаев, независимо от того, какой из них будет фактически возвращен, измененный запрос будет крайне неэффективным.

Таким образом, я хотел бы знать, оценивает ли SQL Server все случаи в операторе CASE или только первый, который удовлетворяет условию CASE?

Ответы [ 4 ]

2 голосов
/ 07 февраля 2011

Нет, он добавляет «предикат passthru» к плану, который гарантирует, что он только оценивает необходимые запросы.См. Подзапросы в выражениях CASE

2 голосов
/ 07 февраля 2011

Оператор CASE SQL Server, как упомянуто в этой статье , использует преимущества короткого замыкания, поэтому в показанном примере он не будет оценивать результаты каждого возможного результата CASE для каждой строки.
Тем не менее, вы все равно получите менее эффективный запрос, чем ваш текущий формат, поскольку тогда вы будете вынуждать все результаты использовать один и тот же план выполнения, который может быть неоптимальным. В зависимости от различий между подзапросами CASE эффект может быть весьма значительным.

0 голосов
/ 07 февраля 2011

предполагая, что объединения одинаковы в каждом подзапросе, я бы попробовал что-то вроде этого:

;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

или я мог бы неправильно понять, что вы пытаетесь сделать;)

0 голосов
/ 07 февраля 2011

Почти всегда вы получите более быстрый результат с решением на основе множеств, чем с процедурным решением в SQL Server (и всех RDMS).

...