pku*_*rov 9 sql-server optimization sql-server-2014
考虑这个由N
自连接组成的查询:
select
t1.*
from [Table] as t1
join [Table] as t2 on
t1.Id = t2.Id
-- ...
join [Table] as tN on
t1.Id = tN.Id
Run Code Online (Sandbox Code Playgroud)
它生成一个执行计划,其中包含 N 次聚集索引扫描和 N-1 次合并连接。
老实说,我看不出有任何理由不优化所有连接并仅执行一次聚集索引扫描,即将原始查询优化为:
select
t1.*
from [Table] as t1
Run Code Online (Sandbox Code Playgroud)
测试:
查询没有意义;它刚刚出现在我的脑海中,我现在对它很好奇。
这是表创建和 3 个查询的小提琴:使用inner join
's、使用left join
's 和混合。您也可以在那里查看执行计划。
似乎left join
在结果执行计划中消除了inner join
s而s 则没有。不过还是不明白为什么。
ype*_*eᵀᴹ 18
首先,让我们假设这(id)
是表的主键。在这种情况下,是的,连接(可以证明)是多余的,可以消除。
现在这只是理论 - 或数学。为了让优化器进行实际的消除,必须将理论转换为代码并添加到优化器的优化/重写/消除套件中。为此,(DBMS) 开发人员必须认为它对效率有很大好处,并且这是一个足够常见的情况。
就个人而言,它听起来不像一个(足够常见)。查询 - 正如您所承认的 - 看起来很愚蠢,审阅者不应该让它通过审阅,除非它得到改进并删除了冗余连接。
也就是说,确实存在消除确实发生的类似查询。Rob Farley 有一篇非常好的相关博客文章:SQL Server 中的 JOIN 简化。
在我们的例子中,我们要做的就是将LEFT
连接更改为连接。请参阅dbfiddle.uk。在这种情况下,优化器知道可以安全地删除连接而不会改变结果。(简化逻辑非常通用,不是自连接的特殊情况。)
当然,在原始查询中,删除INNER
连接也不可能改变结果。但是在主键上自连接根本不常见,因此优化器没有实现这种情况。然而,连接(或左连接)是常见的,其中连接的列是其中一个表的主键(并且通常有外键约束)。这导致了消除连接的第二个选项:添加(自引用!)外键约束:
ALTER TABLE "Table"
ADD FOREIGN KEY (id) REFERENCES "Table" (id) ;
Run Code Online (Sandbox Code Playgroud)
瞧,连接被消除了!(在同一个小提琴中测试):这里
Run Code Online (Sandbox Code Playgroud)create table docs (id int identity primary key, doc varchar(64) ) ; GO
?
Run Code Online (Sandbox Code Playgroud)insert into docs (doc) values ('Enter one batch per field, don''t use ''GO''') , ('Fields grow as you type') , ('Use the [+] buttons to add more') , ('See examples below for advanced usage') ; GO
4 行受影响
Run Code Online (Sandbox Code Playgroud)-------------------------------------------------------------------------------- -- Or use XML to see the visual representation, thanks to Justin Pealing and -- his library: https://github.com/JustinPealing/html-query-plan -------------------------------------------------------------------------------- set statistics xml on; select d1.* from docs d1 join docs d2 on d2.id=d1.id join docs d3 on d3.id=d1.id join docs d4 on d4.id=d1.id; set statistics xml off; GO
身份证 | 文档 -: | :---------------------------------------- 1 | 每个字段输入一批,不要使用“GO” 2 | 字段随着您键入而增长 3 | 使用 [+] 按钮添加更多 4 | 有关高级用法,请参见下面的示例
Run Code Online (Sandbox Code Playgroud)-------------------------------------------------------------------------------- -- Or use XML to see the visual representation, thanks to Justin Pealing and -- his library: https://github.com/JustinPealing/html-query-plan -------------------------------------------------------------------------------- set statistics xml on; select d1.* from docs d1 left join docs d2 on d2.id=d1.id left join docs d3 on d3.id=d1.id left join docs d4 on d4.id=d1.id; set statistics xml off; GO
身份证 | 文档 -: | :---------------------------------------- 1 | 每个字段输入一批,不要使用“GO” 2 | 字段随着您键入而增长 3 | 使用 [+] 按钮添加更多 4 | 有关高级用法,请参见下面的示例
Run Code Online (Sandbox Code Playgroud)alter table docs add foreign key (id) references docs (id) ; GO
?
Run Code Online (Sandbox Code Playgroud)-------------------------------------------------------------------------------- -- Or use XML to see the visual representation, thanks to Justin Pealing and -- his library: https://github.com/JustinPealing/html-query-plan -------------------------------------------------------------------------------- set statistics xml on; select d1.* from docs d1 join docs d2 on d2.id=d1.id join docs d3 on d3.id=d1.id join docs d4 on d4.id=d1.id; set statistics xml off; GO
身份证 | 文档 -: | :---------------------------------------- 1 | 每个字段输入一批,不要使用“GO” 2 | 字段随着您键入而增长 3 | 使用 [+] 按钮添加更多 4 | 有关高级用法,请参见下面的示例
归档时间: |
|
查看次数: |
1734 次 |
最近记录: |