25

我有一个表 ( 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 JOIN我理解 an和 a之间结果的区别LEFT JOIN。在这种情况下,它返回的结果与每个孩子都有父母完全相同。如果我让两个查询都运行,我可以比较数据集并且它们完全相同。

为什么 a跑得比 aLEFT JOIN快那么多INNER JOIN


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

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

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


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

例如,SQL Server中 INNER JOIN 与 LEFT JOIN 性能中的选定答案表明,左连接总是比内连接慢。这个论点是有道理的,但这不是我所看到的。

4

2 回答 2

15

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

强制连接以正确顺序发生的 3 种方法:

  1. 将第一个数据子集选择到临时表(或表变量)中,然后加入它
  2. 使用左连接(请记住,这可能会返回不同的数据,因为它是左连接而不是内连接)
  3. 使用 FORCE ORDER 关键字。请注意,如果表大小或架构发生更改,则查询计划可能不正确(请参阅https://dba.stackexchange.com/questions/45388/forcing-join-order
于 2013-07-14T23:10:41.370 回答
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
于 2013-06-14T04:29:48.847 回答