【问题标题】:SQL Server - unused LEFT JOIN impacts execution planSQL Server - 未使用的 LEFT JOIN 影响执行计划
【发布时间】:2020-06-02 04:28:30
【问题描述】:

我有这样的查询

SELECT TableA.Id FROM TableA
LEFT JOIN TableB ON TableA.Id = TableB.TableAId

在这种情况下,表 B 中的列实际上没有被使用,并且不会影响结果,因为它不是 INNER JOIN。但是执行计划清楚地表明它正在被使用并且它会影响性能。 SQL Server 不应该对其进行优化以消除未使用的操作吗?有没有办法设置一些执行提示来做到这一点或重写查询以仅当它实际存在于 SELECT 或 WHERE 子句中时才使用此连接?

不幸的是,我不能只从查询中删除未使用的联接。在现实生活中,它是一个更复杂的视图,它连接了许多表,并且总是与不同的 SELECT 列表或 WHERE 条件一起使用

【问题讨论】:

  • TableAId 列是否唯一? (否则 LEFT JOIN 可能会生成多行。)
  • @jarlh 是的,它是独一无二的
  • @jarlh 实际上,你是对的,这是因为独特性。 TableB 是一个具有 UNION 语句的视图,显然它阻止 SQL Server 推断它的唯一性。谢谢!
  • "表 B 中的列实际上没有被使用" 什么? "= TableB.TableAId" Re "不能影响结果,因为它不是 INNER JOIN" 左连接返回内连接行加上由空值扩展的不匹配的左表行。你的介绍没有意义。请给minimal reproducible example 并参考它来解释你想说什么。这包括约束,以防您依赖特殊情况 - 它们用于完整性和优化。 PS请通过编辑而不是cmets进行澄清。 PS 你的研究表明了什么?--包括使用 site:stackoverflow.com 的手册和谷歌搜索。 How to Ask

标签: sql sql-server left-join query-performance


【解决方案1】:

LEFT JOIN 可以改变结果,即使它们的列不在结果集中。

看看这两个查询如何返回不同的结果:

create table TableA (TableAId int)
create table TableB (TableBId int, TableAId int)

insert into TableA (TableAId) values (100), (200), (300)
insert into TableB (TableBId, TableAId) values (1, 100), (1, 200), (2, 100), (3, 300)

select TableA.TableAId 
from TableA

select TableA.TableAId 
from TableA
     left join TableB on TableB.TableAId = TableA.TableAId

那是因为如果多行匹配连接条件,那么所有行都会被连接。

【讨论】:

  • 是的,正如@jarlh 评论的那样,这是因为 SQL Server 无法验证 TableB 的唯一性(在我的例子中是带有 union 语句的视图)。为 TableB 添加group by 后,如果它的列未使用,则不会影响执行计划
猜你喜欢
  • 1970-01-01
  • 2010-09-29
  • 2021-07-20
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多