【问题标题】:Is having an 'OR' in an INNER JOIN condition a bad idea?在 INNER JOIN 条件中使用“或”是一个坏主意吗?
【发布时间】:2011-08-19 14:19:02
【问题描述】:

在尝试提高极慢查询的速度(在两个只有约 50,000 行的表上,如果重要的话,在 SQL Server 2008 上需要几个 分钟),我将问题缩小到OR 在我的内部连接中,如:

SELECT mt.ID, mt.ParentID, ot.MasterID
  FROM dbo.MainTable AS mt
  INNER JOIN dbo.OtherTable AS ot ON ot.ParentID = mt.ID
                                  OR ot.ID = mt.ParentID

我将其更改为(我希望是)一对等效的左连接,如下所示:

SELECT mt.ID, mt.ParentID,
   CASE WHEN ot1.MasterID IS NOT NULL THEN
      ot1.MasterID ELSE
      ot2.MasterID END AS MasterID
  FROM dbo.MainTable AS mt
  LEFT JOIN dbo.OtherTable AS ot1 ON ot1.ParentID = mt.ID
  LEFT JOIN dbo.OtherTable AS ot2 ON ot2.ID = mt.ParentID
  WHERE ot1.MasterID IS NOT NULL OR ot2.MasterID IS NOT NULL

.. 查询现在运行大约一秒钟!

OR 置于连接条件中通常是个坏主意吗?还是我只是在我的桌子布局上不走运?

【问题讨论】:

  • 向我们展示执行计划而不是您的查询。
  • 看起来很奇怪的关系
  • @Blindy:好主意。事实证明,执行计划显示了 Quassnoi 在下面提到的内容:第一个查询导致嵌套循环,而第二个查询是通过哈希连接完成的。

标签: sql sql-server sql-server-2008 tsql inner-join


【解决方案1】:

这种JOIN 不适用于HASH JOINMERGE JOIN

它可以表示为两个结果集的串联:

SELECT  *
FROM    maintable m
JOIN    othertable o
ON      o.parentId = m.id
UNION
SELECT  *
FROM    maintable m
JOIN    othertable o
ON      o.id = m.parentId

,它们每个都是等值连接,但是,SQL Server 的优化器不够聪明,无法在您编写的查询中看到它(尽管它们在逻辑上是等价的)。

【讨论】:

  • 这很有道理,谢谢。我仍然不确定我的查询是否有什么特殊之处,或者我是否应该完全避免 ON w=x OR y=z 模式的连接?
  • @ladenedge:这些连接将使用嵌套循环中的表扫描来执行。如果您的表很大,这会很慢。
  • 为了清楚起见,当您说“这些连接”时,您是指ON w=x OR y=z 形式的所有连接? (感谢您的耐心等待!)
  • @ladenedge:可能还有其他条件可以帮助SQL Server 了解需要连接。比如说,如果两个字段都被索引,那么查询SELECT * FROM othertable WHERE parentId = 1 OR id = 2 将使用连接,所以理论上没有什么可以阻止在循环中做同样的事情。 SQL Server 是否真的会建立这个计划,取决于很多因素,但我从未见过它在现实生活中建立。
  • 另请注意,如果您知道它们是不相交的集合,则 union ALL 可以通过避免合并结果集来显着提高性能。
【解决方案2】:

我使用以下代码从条件中获得不同的结果 这对我有用。


Select A.column, B.column
FROM TABLE1 A
INNER JOIN
TABLE2 B
ON A.Id = (case when (your condition) then b.Id else (something) END)

【讨论】:

    【解决方案3】:

    您可以使用 UNION ALL 代替

    SELECT mt.ID, mt.ParentID, ot.MasterID
    FROM dbo.MainTable AS mt
    UNION ALL
    SELECT mt.ID, mt.ParentID, ot.MasterID
    FROM dbo.OtherTable AS ot
    

    【讨论】:

    • UNION ALL 会为您提供与JOIN 相比具有OR 条件的重复项。
    • 对于那个 UNION 是对的。有关更多详细信息,请阅读以下链接union-instead-of-or
    • 是的,但在您的示例中,您使用 union all 编写了它,这与您链接到的文章所描述的不正确。
    猜你喜欢
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2017-05-07
    • 2020-12-12
    相关资源
    最近更新 更多