【问题标题】:SQL Server - Query Short-Circuiting?SQL Server - 查询短路?
【发布时间】:2010-09-27 17:30:50
【问题描述】:

SQL Server 中的 T-SQL 查询是否支持短路?

例如,我有两个数据库,我正在比较两个表之间的数据以匹配并复制一些信息。在一个表中,“ID”字段总是有前导零(例如“000000001234”),而在另一个表中,ID 字段可能有也可能没有前导零(可能是“000000001234”或“1234”)。

所以我匹配这两者的查询是这样的: select * from table1 where table1.ID LIKE '%1234'

为了加快速度,我正在考虑在类似内容之前添加一个 OR,即: 表 1.ID = 表 2.ID 处理两个 ID 都填充零且相等的情况。

这样做是否会通过匹配“=”上的项目而不是评估每一行的 LIKE 来加快查询速度(是否会短路并跳过 LIKE)?

【问题讨论】:

  • table1.ID LIKE '%1234' 会匹配“31234”怎么样?
  • 好吧,搜索过滤器会更像 '%00001234' - 还有一些前导零。

标签: sql sql-server


【解决方案1】:

SQL Server 确实短路 where 条件。 它不能,因为它是基于成本的系统:How SQL Server short-circuits WHERE condition evaluation

【讨论】:

    【解决方案2】:

    以防万一它有用,正如 Mladen Prajdic 的答案中的链接页面所解释的那样,CASE 子句 是短路评估的。

    【讨论】:

      【解决方案3】:

      修复数据库以保持一致

      select * from table1 where table1.ID LIKE '%1234'
      

      将匹配“1234”、“01234”、“00000000001234”,还可以匹配“999991234”。使用 LIKE 几乎可以保证索引扫描(假设 table1.ID 已编入索引!)。清理数据将显着提高性能。

      如果无法清理数据,请编写用户定义函数 (UDF) 以去除前导零,例如

      select * from table1 where dbo.udfStripLeadingZeros(table1.ID) = '1234'
      

      这可能不会提高性能(因为函数必须为每一行运行),但它会消除错误匹配并使查询的意图更加明显

      编辑:如果可能的话,Tom H 建议将 CAST 转换为整数是最好的。

      【讨论】:

      • like 不保证表扫描,如 '%1234' 是表扫描。 like '1234%' 不是表扫描,假设列被索引,它将使用索引找到 1234...
      • @Josh:我说的是“索引扫描”,而不是“表扫描”。
      • @Steven 是的,我不知道为什么,但是当我第一次读到它时,我可以发誓它说的是桌子……我想我变老了;-)
      • 但无论哪种方式,我认为以通配符作为前缀都会导致表扫描,也许这就是我让他们感到困惑的原因。
      【解决方案4】:

      怎么样,

      table1WithZero.ID = REPLICATE('0', 12-len(table2.ID))+table2.ID
      

      在这种情况下,它应该可以使用table1上的索引

      【讨论】:

        【解决方案5】:

        您可以将计算列添加到表中。然后,索引计算列并在连接中使用该列。

        例如:

        Alter Table Table1 Add PaddedId As Right('000000000000' + Id, 12)
        Create Index idx_WhateverIndexNameYouWant On Table1(PaddedId)
        

        那么您的查询将是...

        select * from table1 where table1.PaddedID ='000000001234'
        

        这将使用您刚刚创建的索引来快速返回该行。

        【讨论】:

        • 好。没有 OR,不是 UDF,可索引等
        • 请记住,这将导致插入和更新的(希望是轻微的)命中。好主意,只要这不是问题。
        • 如果您无法将数据修复为一致,这是下一个最佳解决方案
        【解决方案6】:

        您要确保至少有一个表将其实际数据类型用于 ID,并且如果可能,它可以使用索引查找。这取决于您的查询的选择性和匹配率,但要确定应该将哪个转换为另一个。如果您知道必须扫描整个第一个表,那么无论如何您都不能使用搜索,您应该将该 ID 转换为另一个表的数据类型。

        为确保您可以使用索引,也请避免使用 LIKE。例如,最好有:

        WHERE
             T1.ID = CAST(T2.ID AS VARCHAR) OR
             T1.ID = RIGHT('0000000000' + CAST(T2.ID AS VARCHAR), 10)
        

        比:

        WHERE
             T1.ID LIKE '%' + CAST(T2.ID AS VARCHAR)
        

        正如 Steven A. Lowe 所说,第二个查询也可能不准确。

        如果您要使用 T1 中的所有行(换句话说,T2 的左外连接),那么您可能会更好:

        WHERE
             CAST(T1.ID AS INT) = T2.ID
        

        如果您不确定,请对每种方法执行一些查询计划,看看哪种方法最有效。

        不过,绝对最好的方法是按照其他人的建议,如果可能的话,更改表的数据类型以匹配。即使您无法在该项目到期之前完成,也请将其列入近期的“待办事项”清单。

        【讨论】:

          【解决方案7】:

          如果 ID 是纯数字(如您的示例),我建议(如果可能)将该字段更改为数字类型。如果数据库已经在使用中,那么可能很难更改类型。

          【讨论】:

          • 是的,我无法更改源表。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-27
          • 2012-10-06
          • 2013-03-13
          • 2012-05-01
          • 1970-01-01
          • 2011-05-26
          • 1970-01-01
          相关资源
          最近更新 更多