我有一个表(MainTable),其中有600,000多条记录。它通过父/子类型关系中的第二个表(JoinTable)加入自身:

SELECT   Child.ID, Parent.ID
FROM     MainTable
AS       Child
JOIN     JoinTable
      ON Child.ID = JoinTable.ID
JOIN     MainTable
AS       Parent
      ON Parent.ID = JoinTable.ParentID
     AND Parent.SomeOtherData = Child.SomeOtherData

我知道每个子记录都有一个父记录,并且JoinTable中的数据是准确的。

当我运行此查询时,它实际上需要几分钟的时间。但是,如果我使用“左连接”加入“父级”,则运行时间不到1秒:
SELECT   Child.ID, Parent.ID
FROM     MainTable
AS       Child
JOIN     JoinTable
      ON Child.ID = JoinTable.ID
LEFT JOIN MainTable
AS       Parent
      ON Parent.ID = JoinTable.ParentID
     AND Parent.SomeOtherData = Child.SomeOtherData
WHERE    ...[some info to make sure we don't select parent records in the child dataset]...

我了解INNER JOINLEFT JOIN之间的结果差异。在这种情况下,它返回的结果与每个 child 都有 parent 的情况完全相同。如果我让两个查询都运行,我可以比较数据集,它们是完全相同的。

为什么LEFT JOIN的运行速度比INNER JOIN快得多?

更新
检查查询计划,并在使用内部联接时从父数据集开始。进行左连接时,它从子数据集开始。

它使用的索引都是相同的。

我可以强制它总是从 child 开始吗?使用左联接有效,只是感觉不对。

之前曾在这里问过类似的问题,但似乎没有人回答我的问题。

例如在INNER JOIN vs LEFT JOIN performance in SQL Server中选择的答案表明,左联接总是比内联接慢。该论点是有道理的,但这不是我所看到的。

最佳答案

左联接似乎更快,因为强制SQL先执行较小的选择,然后再联接到此较小的记录集。由于某种原因,优化器不希望自然地这样做。

强制以正确顺序进行连接的3种方法:

  • 将第一个数据子集选择到临时表(或表变量)中,然后对其进行联接
  • 使用左联接(请记住,这可能返回不同的数据,因为它是左联接而不是内部联接)
  • 使用FORCE ORDER关键字。请注意,如果表大小或模式更改,则查询计划可能不正确(请参阅https://dba.stackexchange.com/questions/45388/forcing-join-order)
  • 关于sql - LEFT JOIN显着快于INNER JOIN,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17100819/

    10-16 14:55