-1

SQL Server 版本:Microsoft SQL Azure (RTM) - 12.0.2000.8 Oct 1 2020 18:48:35 版权所有 (C) 2019 Microsoft Corporation

在最新版本的 SQL Server(大约 2020 年)中,SQL Server 是否能够优化内部联接,或者在适当的情况下使用左联接是否相关?

换句话说:这个查询是...

select * from MiddleTable
left join LeftTable on MiddleTable.LeftTableId = LeftTable.Id
inner join RightTable on MiddleTable.RightTableId = RightTable.Id
where LeftTable.SomeExtraFilterId = RightTable.SomeExtraFilterId 
and RightTable.AnotherExtraFilterId = 'whatever Id value'

...正如我所期望的那样,比这个查询更有效率吗?

select * from LeftTable
innerjoin MiddleTable on MiddleTable.LeftTableId = LeftTable.Id
inner join RightTable on MiddleTable.RightTableId = RightTable.Id
where LeftTable.SomeExtraFilterId = RightTable.SomeExtraFilterId 
and RightTable.AnotherExtraFilterId = 'whatever Id value'

奖励问题:我的问题有意义吗?还是我完全误解了连接的工作原理——即它从来不是性能上的差异(即行组合数量的差异),而只是语法上的差异(取决于你想用哪个表开始查询) ?

=========

编辑: 我使用 SET STATISTICS IO ON 和 SET STATISTICS TIME ON 来比较查询执行情况。

  • 两个内部连接的结果:

    (受影响的 163 行)表“LeftTable”。扫描计数 0,逻辑读取 326,物理读取 0,页面服务器读取 0,预读读取 0,页面服务器预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 页面服务器读取 0,lob 读取预读为 0,lob 页面服务器预读为 0。

    表“中表”。扫描计数 1,逻辑读取 13,物理读取 0,页面服务器读取 0,预读读取 0,页面服务器预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 页面服务器读取 0,lob 读取预读为 0,lob 页面服务器预读为 0。

    表“右表”。扫描计数 1,逻辑读取 2,物理读取 0,页面服务器读取 0,预读读取 0,页面服务器预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 页面服务器读取 0,lob 读取-预读为 0,lob 页面服务器预读为 0。

    SQL Server 执行时间:CPU 时间 = 0 毫秒,经过时间 = 1 毫秒。总执行时间:00:00:00.040

  • 左连接 + 内连接的结果:

(与上面相同,但在 RightTable 上的逻辑读取量减半,但执行时间加倍)。

我不知道这有多少是由误差范围调用的(这太快了无法确定),但我接受这两个查询没有显着不同,就像我想的那样。

4

1 回答 1

1

您应该检查执行计划。一般来说,这两个查询是等价的,因为第二个on子句将外连接变成inner join. 通常,它是一个where执行过滤的子句。

在许多情况下,外连接和内连接版本会产生非常相似的执行计划,因此性能会非常相似。

一般来说,外连接比内连接对优化器施加更多的约束,所以内连接通常比外连接有更多的优化机会。(在某些极端情况下,内连接执行计划不是最理想的,而外连接解决了这个问题。)

在这种情况下,检测外部联接被过滤为内部联接的情况相当简单,但在其他情况下则更为复杂。我不知道寻找这种模式的数据库有多大。通常,数据库开发人员不会专注于优化编写不佳的查询。

但是,总的来说,您应该编写您想要的查询。在这种情况下,所需的查询似乎是一个内部联接,因此您应该使用它。

于 2020-10-21T13:45:41.627 回答