Является ли замена условной логики операторами CASE эффективной в 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.
Я хотели чтобы уменьшить запрос до следующего:
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 ответов
оператор CASE SQL Server, как указано в в этой статье, использует короткое замыкание, поэтому в показанном примере он не будет оценивать результаты каждого возможного результата случая для каждой строки.
Однако вы все равно получите менее эффективный запрос, чем ваш текущий формат, поскольку вы заставите все результаты использовать один и тот же план выполнения, который может быть не оптимальным. В зависимости от различий между подзапросами CASE эффект может быть довольно значительное.
нет, он добавляет "предикат passthru" к плану, который гарантирует, что он только оценивает необходимые запросы. См.подзапросы в выражениях CASE
предполагая, что соединения одинаковы в каждом подзапросе, я бы попробовал что-то вроде этого:
;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
или я могу быть грубым непониманием того, что вы пытаетесь сделать ;)
вы почти всегда получите более быстрый результат с решением на основе набора против процедурного решения в SQL Server (и всех RDMS).