在 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

在 for 循环中使用 case 语句选择变量

利用Transact-SQL语句完成下列程序

Transact-SQL中的存储过程

SQL Server判断语句(IF ELSE/CASE WHEN )

用Transact-SQL语句完成下列程序