在 Transact-SQL 中用 CASE 语句替换条件逻辑是不是有效?
Posted
技术标签:
【中文标题】在 Transact-SQL 中用 CASE 语句替换条件逻辑是不是有效?【英文标题】:Is replacing conditional logic with CASE statements efficient in Transact-SQL?在 Transact-SQL 中用 CASE 语句替换条件逻辑是否有效? 【发布时间】:2011-02-07 16:10:42 【问题描述】:我有一个执行以下操作的存储过程:
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
条件的第一个情况? p>
【问题讨论】:
+1 表示好问题 【参考方案1】:如this article 中所述,SQL Server 的 CASE 语句确实利用了短路,因此在所示示例中,它不会评估每一行的每个可能的 CASE 结果的结果。 但是,您仍然会得到比当前格式低效率的查询,因为您将强制所有结果共享相同的执行计划,这可能不是最佳的。根据 CASE 子查询之间的差异,效果可能非常显着。
【讨论】:
他当前的格式如何强制每个查询共享相同的计划?当前格式具有单独的查询。每个人都有一些不同的地方,如果他们没有,那为什么会这样呢? 它只会在计划中为每个case
结果添加不同的路径。没有特别的理由认为额外的路径会导致计划的其他部分变得更糟。
你读错了我的答案——它说“仍然会得到比你当前格式低效率的查询”。 OP 的第二部分是他们提出的格式,它比他们当前的格式效率低(尽管可能更容易维护)。
我已经稍微修改了它以消除该句子中无意的歧义。
我相信你是对的,我误读了......但即使是修改后的版本也有问题。正如 Martin 指出的那样,优化器可以简化这种情况。整个查询将有一个计划,但每个案例都会生成自己的最佳路径。但是,如果您说对于一个案例,您可能希望在评估该路径之前从头表开始,那么是的,我同意,这是对优化器的非常微妙的理解和解释。 +1【参考方案2】:
不,它在计划中添加了一个“passthru predicate”,以确保它只评估必要的查询。见Subqueries in CASE Expressions
【讨论】:
【参考方案3】:假设每个子查询中的连接都是相同的,我会尝试这样的事情:
;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
否则我可能会严重误解您要做什么;)
【讨论】:
"这里,DetailTable 没有加入到与第一种情况相同的表中。"注意评论。这不是同一张桌子......【参考方案4】:在 SQL Server(以及所有 RDMS)中,使用基于集合的解决方案与基于过程的解决方案相比,您几乎总能获得更快的结果。
【讨论】:
它是基于设置的。他在问哪个“集合”会更快。 If 语句不是基于 SQL Server 设置的。 对,但是在IF之后,会有一个SQL Statement被执行。 “工作”是在一个 SET 中完成的......与 sql 相比,IF 的评估是微不足道的。你把一个简单的格言发挥到了极致。我们说基于集合更好,但这并不意味着第一行代码会影响性能。这意味着不要逐行循环和处理表格。 并非如此。据我们所知,他需要每隔几秒钟运行一次。以上是关于在 Transact-SQL 中用 CASE 语句替换条件逻辑是不是有效?的主要内容,如果未能解决你的问题,请参考以下文章
verilog中用if语句替换case D idea: one: two: three: end case