SQL CASE vs JOIN效率

时间:2009-06-16 18:03:42

标签: sql-server

在我的MS SQL Server数据库中,我根据一列中的各种不同代码提取交易数据。

更有效率:

  • 为WHERE子句中的每个代码反复加入同一个表

  • 在整个表格上做多个案例陈述(如下所示)

  • 在整个表格上做多个案例陈述但是用WHERE SubsidCde IN ('AA','BA','BB', etc)条款限制

我们每秒运行这么多查询,即使我已经尝试了所有3种方法,但我没有得到明确的结果。

SELECT
    SUM(CASE WHEN Subsid_Cde = 'AA' THEN Trans_Amt END),0) [AA],
    SUM(CASE WHEN Subsid_Cde = 'BA' THEN Trans_Amt END),0) [BA],
    SUM(CASE WHEN Subsid_Cde = 'BB' THEN Trans_Amt END),0) [BB]
FROM
    Transactions

--  There are 8 more rows like this, using a different code for each line

4 个答案:

答案 0 :(得分:4)

如果您对Subsid_Cde字段的所有可能(或大多数)值进行求和,则CASE会更快,因为它不会多次扫描表,因为它会聚合总和。如果您只查找可能的Subsid_Cde字段的一小部分,那么单独的选择/连接(以及Subsid_Cde上的索引)将更快地工作。

您需要学习阅读执行计划,然后您才能自己想出这些事情。

另外,您也可以将Subsid_Cde上的GROUP BY包装到PIVOT子句中(google for PIVOT MS SQL SERVER 2005)

答案 1 :(得分:2)

3是你最好的选择。它易于阅读,以后很容易修改,它应该使用你已定义并期望使用的索引(仍然,检查)。

- 1有时您必须加入同一张桌子。但这不是其中之一,并且每次需要包含新的Subsid_Cde时都会加入,这样可以在不真正获得任何内容的情况下获得不太可读的SQL。

- 2事务表往往会变得非常大,所以你永远不想扫描整个表。 所以#2肯定会被淘汰,除非您在查询中使用的代码无论如何都会为您提供所有行。

答案 2 :(得分:1)

使用此:

SELECT  (
        SELECT  SUM(Trans_Amt)
        FROM    Transactions
        WHERE   Subsid_Cde = 'AA'
        ) AS sum_aa,
        (
        SELECT  SUM(Trans_Amt)
        FROM    Transactions
        WHERE   Subsid_Cde = 'BB'
        ) AS sum_bb

,没有外部FROMWHERE条款。

SQL Server 2005+中,请使用:

SELECT  [AA], [BB]
FROM    (
        SELECT  trans_amt, subsid_cde
        FROM    transactions
        ) q
PIVOT   (
        SUM(trans_amt)
        FOR subsid_cde IN (['AA'], ['BB'])
        )

答案 3 :(得分:0)

当您执行这样的任务时,有一些非常重要的注意事项。

  • CASE 的限制
  • CASE 附带的所有权
<块引用>

CASE 是表达式而不是语句。

代码将重新评估每个 WHEN 的“所有相关内容”。

在您的 CASE 实例中,它正在查看原始表并且不会评估超过一个 WHEN,因此它不会重新查询,它会执行一次扫描或根据您的索引查找并返回结果,并为每个 CASE 执行该操作,但它必须为 JOIN 执行该操作,事实上您的 结果已编码到案例中< /em> 意味着系统不必搜索要检查的值

最后一点意义重大,因为它对企业和作为编码人员的您都有重大影响。

Aaron Bertrand 写了一篇非常棒的文章,详细介绍了“案件的肮脏秘密” https://sqlperformance.com/2014/06/t-sql-queries/dirty-secrets-of-the-case-expression

总结是,它可能会重新查询每个 WHEN,这听起来还不错,但是如果您的 SQL 查询受增长因子影响很差,那么您的 CASE解决方案不可扩展,如果您使用任何在调用时重新评估的功能[RAND()是罪魁祸首],它不仅会在某些情况下产生不一致的结果,而且可能如果您的查询具有“涉及 N 的幂的大 O 表示法”(这是一种非常技术性的说法,使用 Sort、Union、Distinct 或其他形式的被动排序调用或更糟,则对您的输出产生巨大影响,正在采用没有最新统计数据的过时计划。这意味着 CASE 可能会翻倍、三倍或我喜欢称之为“(N)WHEN”的怪物的查询时间指数迭代问题。

<块引用>

您的 CASE 将需要“技术维护”(每当实施新代码时, 将不得不重新编码以将其考虑在内),JOIN 将需要“USER MAINTENANCE”(用户更改查找表,并且您的查询已更新,而您无需取得任何所有权)

“技术维护”使面临陷入业务失误后果的风险

您总是希望编写解决方案以最大限度地减少您对数据吞吐量的所有权,因为您不想在法庭上谈论您在触及业务逻辑时的一小部分参与,而是想在家中您的家人或在度假时没有接到有关“抄送”的电话,他们刚刚添加并希望在您的报告中汇总。

CASE 的实例中,您已经将自己编码为一种情况,您正在执行业务逻辑,业务应该在查找表中决定应该是一个 {{ 1}}。

简而言之,当企业提出新代码时,您的报告看不到该输出,这将导致您进行生产抽奖,尤其是当您去度假并发现自己是唯一知道该代码的人时您的 JOIN 的存在,您可能不会认为它是一种开销,但您不会长远考虑,因为从长远来看,记忆是模糊的,您可能会发现自己正在寻找您的 CASE然后在将来添加它,您不会为此感谢自己。

为了节省 4 秒,您给自己带来了不便

牺牲自己来改变速度并不是好的编码习惯。