具有复杂条件的INNER JOIN会大大增加执行时间

时间:2012-09-09 11:04:21

标签: sql sql-server performance inner-join

我有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&表2。所以我的查询很简单:

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

结果更令人惊讶:从几个小时(第一个案例)的执行时间减少到2-3秒!

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

3 个答案:

答案 0 :(得分:4)

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

  1. “Hash join”:在其中一个表上创建一个哈希表,用于在第二个表中查找值。
  2. “合并连接”:对密钥上的两个表进行排序,然后按顺序读取结果。
  3. “索引查找”:使用索引在一个表中查找值。
  4. “嵌套循环”:将每个表中的每个值与另一个表中的所有值进行比较。
  5. (并且有这些变体,例如使用索引而不是表,使用分区,以及处理多个处理器。)不幸的是,在SQL Server Management Studio中,(3)和(4)都显示为嵌套循环连接。如果仔细观察,可以区分节点中的参数。

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

    当您从单个相等切换到“in”或一组“或”条件时,连接条件已从等值连接变为非等值连接。我的观察是SQL Server在这种情况下做了一个糟糕的优化工作(并且,公平地说,我认为其他数据库的功能几乎完全相同)。从良好的连接算法到嵌套循环算法,您的性能受到了打击。

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

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

      从table1 t1左外连接      table2 t2_11      在t1.p1 = t2_11.p1左外连接      table2 t2_12      在t1.p1 = t2_12.p2左外连接      table2 t2_21      在t1.p2 = t2_21.p2左外连接      table2 t2_22      在t1.p2 = t2_22.p2

    4. 然后在SELECT中使用case / coalesce逻辑来获取您实际需要的值。虽然这可能看起来更复杂,但应该非常有效。

答案 1 :(得分:2)

你可以使用4个查询和Union那里结果

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

答案 2 :(得分:0)

使用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

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