【问题标题】:CASE statement versus temporary tableCASE 语句与临时表
【发布时间】:2016-05-31 16:08:23
【问题描述】:

在将代码转换为文本时,我可以在两种不同的技术之间进行选择:

insert into #TMP_CONVERT(code, value)
 (1, 'Uno')
,(2, 'Dos')
,(3, 'Tres')
;

coalesce(tc.value, 'Unknown') as THE_VALUE
...
LEFT OUTER JOIN #TMP_CONVERT tc
  on tc.code = x.code

或者

case x.code
when 1 then 'Uno'
when 2 then 'Dos'
when 3 then 'Tres'
else 'Unknown'
end as THE_VALUE

该表有大约 2000 万行。 代码查找表的典型大小为 10 行。

我宁愿#1,但我不喜欢左外连接。

我的问题是:

  1. 一个比另一个快吗?

  2. 是否有任何 SQL 引擎对此进行优化?那就是:它只是将表读入内存,本质上是case语句逻辑吗?

我碰巧在使用 tsql,但我想知道任意数量的 RDBM 系统,因为我使用了多个。

[编辑以澄清不喜欢 LEFT OUTER JOIN] 我在需要时使用 LEFT OUTER JOINS,但每当我使用它们时,我都会仔细检查我的逻辑和数据以确认我确实需要它们。然后我在代码中添加一个注释,说明我为什么使用 LEFT OUTER JOIN。当然我在使用 INNER JOIN 的时候也要做类似的练习;也就是说:确保我没有丢弃数据。

【问题讨论】:

  • 我很好奇有一个用例会支持在代码中而不是静态表中查找数据。遇到任何情况,我都会创建一个用户无需更改代码即可编辑的表格。
  • 可能值得一读 Eric Lippert 的优秀文章Which is faster?:“...如果你有两匹马,并且你想知道哪两匹马跑得更快,那就让你的马赛跑吧。不要写短马匹的描述,将它们发布到互联网上,让随机的陌生人猜猜哪个更快!”
  • 对 2000 万行运行它们会得到什么结果?

标签: sql-server tsql


【解决方案1】:

使用join 会产生一些开销。但是,如果将code 设为主集群键,那么两者的性能可能相当——join 甚至胜出。如果没有索引,我预计case 会比left join 稍好一些。

这些只是猜测。不过,与所有性能问题一样,您应该检查系统上的数据。

我也想对你不喜欢left joins 做出反应。这些为 SQL 提供了重要的功能,是解决这个问题的正确方法。

【讨论】:

    【解决方案2】:

    为连接执行的代码可能远远多于为硬编码的case 选项执行的代码。

    执行计划将有一个额外的连接迭代器以及一个额外的扫描或查找运算符(取决于合适索引的可用性)。从积极的方面来说,这 10 行可能都适合#TMP_CONVERT 中的一个页面,并且无论如何这将在内存中,也是一个临时表,它不会每次都为获取和释放行锁而烦恼,但仍然是代码锁定页面,找到正确的行,并从中破解所需的列值超过 20,000,000 次迭代可能会增加一些可测量的 CPU 时间,与在硬编码的值列表中查找相比(可能您可以尝试嵌套 CASE语句,执行二进制搜索并避免在那里需要 10 个分支)。

    但即使存在可测量的时间差异,它在整个查询时间中的比例仍然可能不是特别重要。测试一下。让我们知道您发现了什么...

    【讨论】:

      【解决方案3】:

      您也可以通过使用with 构造来避免在这种情况下创建临时表。所以你的查询可能是这样的。

      WITH TMP_CONVERT(code,value) AS -- Semicolon can be required before WITH.
      (
          SELECT * FROM (VALUES (1,'UNO'), 
                                (2,'DOS'),
                                (3,'Tres')
          ) tbl(code,value)
      )
      coalesce(tc.value, 'Unknown') as THE_VALUE
      ...
      LEFT OUTER JOIN TMP_CONVERT tc
        on tc.code = x.code
      

      甚至可以使用子查询:

      coalesce(tc.value, 'Unknown') as THE_VALUE
      ...
      LEFT OUTER JOIN (VALUES (1,'UNO'), 
                              (2,'DOS'),
                              (3,'Tres')
              ) tc(code,value) 
              ON tc.code = x.code
      

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多