带有子查询的CASE是否会在不匹配的条件下执行子查询?

问题描述 投票:0回答:1

我想实现从连接表中获取特定列的数据的逻辑,但如果失败,则回退到子查询:

SELECT 
    m.a, m.b,
    CASE 
        WHEN o.c IS NOT NULL 
            THEN o.c
            ELSE (SELECT TOP 1 c FROM other_table 
                  WHERE <predicate over o.* and m.*> 
                  ORDER BY ...)
    END as c
FROM 
    main_table m
LEFT JOIN 
    other_table o ON m.key = o.key

功能上它工作得很好,但我想知道我是否真的从我的

CASE
运算符中获得任何性能优势。我们的想法是,按键匹配几乎适用于所有情况,但对于一小部分行,我们需要回退到更昂贵的
TOP 1
搜索而不是
other_table
。优化器是否足够智能来捕获此逻辑,或者它无论如何都会评估每个输出行的子查询?

我正在尝试从该计划中学习,但说实话,我不太确定如何解释它。

最上面的分支是

LEFT JOIN
,速度超级快。

底部分支是

TOP 1
子查询(本质上是
LEFT JOIN
的变体)。

突出显示的节点是

CASE
运算符。

我尝试根据“慢”分支中获得的行数来理解逻辑:

但这些数字对我来说没有意义。查询返回的总行数(=

main_table
中的行数)为 3127。LEFT JOIN
not join
行数为 328。该计划显示从 289 行开始的恒定扫描的两个叶子。我可以理解单独看到 328 行,但我不明白什么是 289。为什么有两个,连接成 578,然后合并回 289?

请帮助我理解该计划。是否有“有条件地进入嵌套循环”之类的事情?看起来最后一个嵌套循环调用底部分支,不管......我需要重写查询吗?

sql sql-server query-optimization
1个回答
0
投票

CASE 表达式按顺序计算其条件并停止 满足第一个条件

参见https://learn.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql?view=sql-server-ver16

因此仅当第一个条件为 false 时才会运行选择

并非所有可能性都是如此,如果您使用聚合,它将首先被处理,这在上面的链接中提到。

首先计算出现在 CASE 表达式的 WHEN 参数中的聚合表达式,

我们在这里有一些线程,人们将相关子查询与内连接进行比较,但没有发现速度上的任何差异。

© www.soinside.com 2019 - 2024. All rights reserved.