SQL JOIN语句的顺序会影响性能吗?

64

我刚整理了一些 SQL 代码,然后发现了这个查询:

SELECT 
        jm.IMEI ,
        jm.MaxSpeedKM ,
        jm.MaxAccel ,
        jm.MaxDeccel ,
        jm.JourneyMaxLeft ,
        jm.JourneyMaxRight ,
        jm.DistanceKM ,
        jm.IdleTimeSeconds ,
        jm.WebUserJourneyId ,
        jm.lifetime_odo_metres ,
        jm.[Descriptor]
FROM    dbo.Reporting_WebUsers AS wu WITH (NOLOCK)
        INNER JOIN dbo.Reporting_JourneyMaster90 AS jm WITH (NOLOCK) ON wu.WebUsersId = jm.WebUsersId
        INNER JOIN dbo.Reporting_Journeys AS j WITH (NOLOCK) ON jm.WebUserJourneyId = j.WebUserJourneyId
WHERE   ( wu.isActive = 1 )
        AND ( j.JourneyDuration > 2 )
        AND ( j.JourneyDuration < 1000 )
        AND ( j.JourneyDistance > 0 )

我的问题是连接的顺序是否会对性能产生影响,对于上述查询,我会这样做:

FROM dbo.Reporting_JourneyMaster90 AS jm

然后将另外2个表格与该表格连接


1
尝试运行两个并查看执行计划。它们有任何不同吗?我不会期望它们有什么不同。 - Jeff Rosenberg
1
我从未听说过它会影响性能。 - Steven Wexler
1
如果一个如此简单的查询很慢,我会认为你需要查看索引。 - HLGEM
1
它不慢 - 只是看起来很奇怪,你会从一个表中选择所有列而不将其作为主要的FROM表,但这让我思考了性能问题,因为它需要可扩展性,以处理大量数据。 - user1987162
1
可能是重复的问题:SQL Server 2005 - Inner Joins 的顺序 - bummi
6个回答

64

SQL2008R2服务器中的连接顺序确实会影响查询性能,尤其是在对多个表应用 where 子句的大量表连接查询中。

虽然优化过程中可以更改连接顺序,但优化器不会尝试所有可能的连接顺序。它在找到可行解决方案时便停止了,因为优化本身就会消耗宝贵的资源。

我们曾经看到一些执行时间超过1分钟的查询语句,仅通过改变 join 表达式的顺序就将其性能提高到亚秒级别。请注意,这些都是具有12到20个连接和多个表上的where子句的查询。

诀窍在于设置连接顺序以帮助查询优化器找出什么是最有效的。您可以使用“ Force Order”,但那可能太死板了。请尽量确保连接顺序从减少数据最多的表开始。


3
我已经使用 SQL Server 工作超过 10 年,第一次发现 JOIN 顺序会影响性能,就像这个回答中所说的那样。我感到困惑,因为我一直以为优化器是最懂的,但在寻找其他遇到相同问题的人时偶然发现了这个。是的,我的统计数据都是最新的。 - Jim Clouse
3
这可能只是参数嗅探问题,即对查询进行任何更改都会改善情况。 - Martin Smith
6
甚至Grant Fritchey的基于成本的优化器书籍都谈到了这种情况,即“优化器”放弃处理复杂查询的特定场景。他甚至能够使用Microsoft的演示数据库进行演示。 - John Zabroski
2
这应该是正确的答案。顺便说一下:我的复杂、大型 Oracle 查询在我改变连接顺序之前从未完成过。 - ColinMac
甚至不需要太多的连接。我在一个只有4个表的查询中体验到了显著的差异(~200ms vs ~7500ms)。一个连接子句使用了IN表达式,但是除此之外,这是一个相当小的查询。 - BVernon
甚至不需要太多的连接。在一个只有4个表的查询中,我发现了一个显著的差异(约200毫秒对比约7500毫秒)。其中一个连接子句使用了IN表达式,但整个查询相对较小。 - undefined

42

不,联接顺序在优化期间会发生变化。

唯一的例外是选项FORCE ORDER,它将强制联接按照您指定的确切顺序发生。


3
我刚刚使用MySQL举了一个例子,这里确实很重要,因为我在另一张表中加入日期进行排序。更改排序方式可以减少20%的执行时间,而添加分页则可以将执行时间减少80%。所以我想这取决于具体情况。 - smerlung
在我目前在SQL Server上工作的查询中,改变JOIN的顺序确实会改变计划,并且会产生显著的差异。不过,Kitster的答案解释了原因。 - BVernon
在我目前在SQL Server中工作的查询中,更改JOIN顺序确实会改变计划并产生显着差异。不过,Kitster的答案解释了原因。 - BVernon

12

我有一个明显的内连接影响性能的例子。这是两个表之间的简单连接。其中一个表有5000多万条记录,另一个表只有2000条。如果我从较小的表中进行选择并连接更大的表,则需要5分钟以上。

如果我从较大的表中进行选择并连接更小的表,则需要2分30秒。

这是使用SQL Server 2012所得到的结果。

对我来说,这是违反直觉的,因为我正在使用最大的数据集进行初始查询。


18
如能展示两种情况的执行计划,将有助于你的回答。 - PeterVermont
1
也许 where 子句将大表限制为一个小集合,而无法减少您的较小表? - user2173353

7
通常情况下不会。我不能百分之百确定这适用于Sql-Server,但在Postgres中,查询规划器保留重新排序内部连接的权利。例外情况是当您达到一个阈值时,超过这个阈值,更改它们的顺序的成本太高了,因此将不再进行重新排序。

7
JOIN语句的顺序并不重要,查询引擎会根据索引和其他因素重新组织它们的顺序。为了测试,请执行以下操作:
1. 选择“显示实际执行计划”,然后运行第一个查询。 2. 更改JOIN顺序,然后再次运行查询。 3. 比较执行计划。
由于查询引擎会根据其他因素重新组织JOIN语句的顺序,所以它们应该是相同的。如其他答案中所述,您可以使用OPTION (FORCE ORDER)命令来使用您想要的顺序,但这可能不是最有效的方法。一般而言,JOIN顺序应该是将记录最少的表放在顶部,记录最多的表放在底部,因为在某些DBMS引擎中,顺序可能会有所不同,如果使用FORCE ORDER命令来限制结果,则可能会有所帮助。

2
这个答案不太正确。我刚刚按照你建议的做了,查询运行时间减少了25%。此外,为了确保这不是巧合,我使用相同的逻辑对我的查询中的另一个CTE进行了更改,结果运行时间增加了60%。 - AcePL
不幸的是,改变连接顺序确实会改变我正在处理的查询计划。因此,我认为你的意思是连接顺序不应该有影响,但有时确实会有影响。 - BVernon

-5

错误。对于 SQL Server 2005,这确实很重要,因为您从 FROM 子句的开头就限制了数据集。如果您从 2000 条记录开始而不是 200 万条,那么查询速度会更快。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接