【问题标题】:INNER JOIN with complex condition dramatically increases the execution time复杂条件的 INNER JOIN 显着增加了执行时间
【发布时间】:2012-09-02 13:02:11
【问题描述】:

我有 2 个表,其中有几个相同的字段需要在 JOIN 条件下链接。例如。在每个表中都有字段:P1,P2。我想编写以下连接查询:

SELECT ... FROM Table1
   INNER JOIN
   Table2
      ON    Table1.P1 = Table2.P1
         OR Table1.P2 = Table2.P2
         OR Table1.P1 = Table2.P2
         OR Table1.P2 = Table2.P1

如果我有巨大的表,这个请求会执行很多时间。

我试图测试仅具有一个条件的查询请求将持续多长时间。首先,我以这种方式修改了表格,所有来自 P2 和 P1 的数据都作为新行复制到了 Table1 和 Table2 中。所以我的查询很简单:

SELECT ... FROM Table1 INNER JOIN Table2 ON Table1.P = Table2.P

结果更令人惊讶:执行时间从数小时(第一种情况)减少到 2-3 秒!

为什么会如此不同?这是否意味着复杂的条件总是会降低性能?我该如何改善这个问题?可能是 P1,P2 索引会有所帮助吗?我想保持第一个数据库模式,而不是移动到一个字段 P。

【问题讨论】:

标签: sql sql-server performance inner-join


【解决方案1】:

查询不同的原因是优化器使用了连接策略。基本上有四种方式可以连接两个表:

  1. “哈希联接”:在其中一个表上创建一个哈希表,用于查找第二个表中的值。
  2. “合并联接”:按键对两个表进行排序,然后按顺序读取联接的结果。
  3. “索引查找”:使用索引在一个表中查找值。
  4. “嵌套循环”:将每个表中的每个值与另一个表中的所有值进行比较。

(还有一些变化,例如使用索引而不是表、使用分区以及处理多个处理器。)不幸的是,在 SQL Server Management Studio 中,(3) 和 (4) 都显示为嵌套循环连接。如果仔细观察,可以从节点中的参数看出区别。

在任何情况下,您的原始连接都是前三个连接之一——而且速度很快。这些连接基本上只能用于“等连接”。也就是说,当连接两个表的条​​件包含相等运算符时。

当您从单个相等切换到“in”或一组“or”条件时,连接条件已从等连接变为非等连接。我的观察是,在这种情况下,SQL Server 在优化方面做得很糟糕(而且,公平地说,我认为其他数据库也做同样的事情)。您的性能影响是从一个好的连接算法到嵌套循环算法的影响。

如果不进行测试,我可能会建议以下一些策略。

  1. 在两个表的 P1 和 P2 上建立索引。 SQL Server 甚至可以将索引用于非等值连接。
  2. 使用其他解决方案中建议的联合查询。应正确优化每个查询。
  3. 假设这些是 1-1 连接,您也可以将其作为一组多个连接来执行:

    from table1 t1 左外连接 表2 t2_11 on t1.p1 = t2_11.p1 左外连接 表2 t2_12 在 t1.p1 = t2_12.p2 上左外连接 表2 t2_21 on t1.p2 = t2_21.p2 左外连接 表2 t2_22 在 t1.p2 = t2_22.p2

然后在 SELECT 中使用 case/coalesce 逻辑来获得您真正想要的值。虽然这可能看起来更复杂,但它应该非常有效。

【讨论】:

    【解决方案2】:

    你可以使用4个查询和联合那里的结果

    SELECT ... FROM Table1
    INNER JOIN
    Table2
      ON    Table1.P1 = Table2.P1
    UNION
    SELECT ... FROM Table1
    INNER JOIN
    Table2
      ON   Table1.P1 = Table2.P2
    UNION
    SELECT ... FROM Table1
    INNER JOIN
    Table2
      ON    Table1.P2 = Table2.P1
    UNION
    SELECT ... FROM Table1
    INNER JOIN
    Table2
      ON   Table1.P2 = Table2.P2
    

    【讨论】:

    • 这将扩展为与 OP 相同的查询。它仍然会以嵌套循环连接结束。
    • @Kaushal,10 倍!第二个建议很快,所以我会使用它。但是还是不明白这只是MS SQL还是常见问题?
    • 联合解决方案+1,一些rdbms会根据其他CBO变量自动将多个OR条件转换为联合
    • @Sergey - 这是多个“或”的问题。如果这对你有帮助,请不要忘记接受答案,这样它也将帮助其他人。
    • @Kaushal - 我如何接受答案?投票了吗? - 它说我不能这样做,因为我的声誉很低。它是在回答“这篇文章对您有用吗?” - 是的,我已经回答了。可能是别的什么?
    【解决方案3】:

    使用 CTE 有助于提高性能吗?

    ;WITH Table1_cte 
    AS
    (
    SELECT 
          ...
          [P] = P1
    FROM Table1
    UNION   
    SELECT 
          ...
          [P] = P2
    FROM Table1
    )
    , Table2_cte 
    AS
    (
    SELECT 
          ...
          [P] = P1
    FROM Table2
    UNION   
    SELECT 
          ...
          [P] = P2
    FROM Table2
    )
    SELECT ... FROM Table1_cte x
       INNER JOIN
       Table2_cte y
          ON x.P = y.P
    

    我怀疑,就处理器而言,以上只是相同复杂条件的不同语法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      • 2014-07-07
      • 1970-01-01
      • 2021-06-06
      相关资源
      最近更新 更多