LEFT JOIN明显快于INNER JOIN

时间:2013-06-14 03:52:35

标签: sql performance sql-server-2005 join

我有一张表(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中的数据是精确的。

当我运行此查询时,运行需要几分钟。但是,如果我使用左连接加入Parent,则需要< 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之间的结果差异。在这种情况下,它返回的结果完全相同,因为每个孩子都有父母。如果我让两个查询都运行,我可以比较数据集,它们完全相同。

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


UPDATE 检查查询计划,使用内部联接时,它以Parent数据集开头。在进行左连接时,它以子数据集开始。

它使用的索引都是一样的。

我可以强迫它始终与孩子一起开始吗?使用左连接有效,只是感觉不对。


以前曾在此问过类似的问题,但似乎没有人回答我的问题。

e.g。 INNER JOIN vs LEFT JOIN performance in SQL Server中选定的答案表示左连接总是慢于内连接。这个论点是有道理的,但这不是我所看到的。

2 个答案:

答案 0 :(得分:12)

左连接似乎更快,因为SQL被迫首先执行较小的选择,然后加入这个较小的记录集。出于某种原因,优化者不希望自然地这样做。

强制联接按正确顺序发生的3种方法:

  1. 选择第一个数据子集到临时表(或表变量)然后加入它
  2. 使用左连接(并记住这可能返回不同的数据,因为它是左连接而不是内连接)
  3. 使用FORCE ORDER关键字。请注意,如果表大小或模式更改,则查询计划可能不正确(请参阅https://dba.stackexchange.com/questions/45388/forcing-join-order

答案 1 :(得分:2)

试试这个。同样的结果,不同的方法:

SELECT c.ID, p.ID 
FROM
(SELECT   Child.ID, JoinTable.ParentID
FROM     MainTable
AS       Child
JOIN     JoinTable
      ON Child.ID = JoinTable.ID) AS c
INNER JOIN 
(SELECT   Parent.ID, JoinTable.ID
FROM     MainTable
AS       Parent
JOIN     JoinTable
      ON Parent.ID = JoinTable.ParentID
     AND Parent.SomeOtherData = Child.SomeOtherData) AS p
ON c.ParentID = p.ID

如果没有帮助,请使用cte:

;WITH cte AS
(SELECT   Child.ID, JoinTable.ParentID
FROM     MainTable
AS       Child
JOIN     JoinTable
      ON Child.ID = JoinTable.ID)
SELECT cte.ID, Parent.ID
FROM cte INNER JOIN 
MainTable
AS       Parent
      ON Parent.ID = cte.ParentID
     AND Parent.SomeOtherData = cte.SomeOtherData
相关问题