SQL server 内部实现了三种类型的内连接运算,大多数人从来没有听说过这些连接类型,因为它们不是逻辑连接也很少被用于代码中。那么它们什么时候会被用到呢?答案是要依情况而定。这就意味着要依赖于记录集和索引。查询优化器总是智能的选择最优的物理连接类型。我们知道SQL优化器创建一个计划开销是基于查询开销的,并依据此来选择最佳连接类型。
那查询优化器究竟是怎样从内部选择连接类型的呢?
SQLServer在内部为查询优化器对连接类型的选择实现了一些算法,让我们来看下面的一些练习示例,最后来做总结。
首先我给出一些基本的思想,连接是怎样工作什么时候工作,优化器又是怎样决定使用哪种类型的内连接。
·取决于表大小
· 取决于连接列是否有索引
·取决于连接列是否排序
测试环境:
内存:4GB
数据库服务器:SQLServer 2008 (RTM)
create table tableA (id int identity ,name varchar(50))
declare @i int
set @i=0
while (@i<100)
begin
insert into tableA (name)
select name from master.dbo.spt_values
set @i=@i+1
end
--select COUNT(*) from dbo.tableA --250600
go
create table tableB (id int identity ,name varchar(50))
declare @i int
set @i=0
while (@i<100)
begin
insert into tableB (name)
select name from master.dbo.spt_values
set @i=@i+1
end
-- select COUNT(*) from dbo.tableB --250600
select * from dbo.tableA A join tableB B
on (a.id=b.id)
测试1:大表,没有索引
现在来创建一个聚族索引:
create unique clustered index cx_tableA on tableA (id)
create unique clustered index cx_tableB on tableB (id)
测试1:大表,有索引
如果连接中的任何一个表有索引那么将采用Hash Join。我并没有贴上所有结果截图,如果你感兴趣你可以删除任何一个表中的索引来做测试。
测试2:中表,没有索引
首先创建表:
create table tableC (id int identity,name varchar(50))
insert into tableC (name)
select name from master.dbo.spt_values
-- select COUNT(*) from dbo.tableC --2506
create table tableD (id int identity,name varchar(50))
insert into tableD (name)
select name from master.dbo.spt_values
select * from dbo.tableC C join tableD D
on (C.id=D.id)
-- select COUNT(*) from dbo.tableD --2506
测试2:中表,有索引
首先还是创建一个聚族索引:
create unique clustered index cx_tableC on tableC (id)
create unique clustered index cx_tableD on tableD (id)
对于中等大小的表,如果连接中的任何一个表有索引,那么将采用Merge Join。
测试3:小表,没有索引
create table tableE (id int identity,name varchar(50))
insert into tableE (name)
select top 10 name from master.dbo.spt_values
-- select COUNT(*) from dbo.tableE --10
create table tableF (id int identity,name varchar(50))
insert into tableF (name)
select top 10 name from master.dbo.spt_values
-- select COUNT(*) from dbo.tableF --10
测试3:小表,有索引
创建聚族索引:
create unique clustered index cx_tableE on tableE (id)
create unique clustered index cx_tableF on tableF (id)
对于小表,如果任何一个表中有索引,那么将采用Nested Loop Join。
同样也可以从另一个方向来做比较,比如大表对比中表对比小表。
select * from dbo.tableA A join tableC C
on (a.id=C.id)
select * from dbo.tableA A join tableE E
on (a.id=E.id)
select * from dbo.tableC C join tableE E
on (C.id=E.id)
在这种情况下若所有或部分表都有索引则采用Nested Loop Join,如果都没有则使用HashJoin。
当然你也可以强制优化器使用任何一种连接类型,但这并不是一种值得推荐的做法。查询优化器很智能,能够动态的选择最优的一个。这里我只是显示调用了MergeJoin,所以优化器使用MergeJoin替代本来应使用HashJoin (测试1没有索引)。
select * from dbo.tableA A join tableB B
on (A.id=B.id)option (merge join)
select * from dbo.tableA A inner merge join tableB B
on (A.id=B.id)
表1 测试唯一聚族索引
根据上表:
Ø如果两个表都没有索引则查询优化器内部会选择Hash Join
Ø如果两个表都有索引则内部会选择Merge Join(大表)/NestedLoop Join(小表)
Ø如果其中的一个表有索引则查询优化器内部会选择Merge Join(中表)/HashJoin(大表)/NestedLoop Join(小表&大表 vs 小表)
表2 测试聚族索引(create
clustered index
cx_tableA on
tableA (id))
|
Table size
|
With index (Both)
|
Without Index(Both)
|
Either of table has index
|
|
Big (Both)
|
HASH
|
HASH
|
HASH
|
|
Medium (Both)
|
HASH
|
HASH
|
HASH
|
|
Small (Both)
|
NESTED LOOP
|
NESTED LOOP
|
HASH
|
|
Big Vs Small(medium)
|
HASH
|
HASH
|
HASH
|
|
根据上表:
这个测试是在没有使用唯一聚族索引下完成,可以知道如果创建索引的时候没有使用UNIQUE关键字则无法保证SQLServer会知道这是UNIQUE数据,所以它默认会创建4字节整数来作为唯一标识符。
根据上表如果创建聚族索引没有使用Unique关键字则不会使用MergeJoin。
谢谢@Dave的邮件,现在加上第二个图表了。
总结:
Merge Join
Merge Join是为那些在连接列上有索引的表,索引可以是聚族索引或者非聚族索引。Merge是这种情况最好的Join类型,需要两个表都有索引,所以它已经排好序并更容易匹配和返回数据。
Hash Join
Hash Join是为那些没有索引或者其中任一个有索引的大表。对于这种情况它是最好的Join类型,为什么呢?因为它能够很好的工作于没有索引的大表和并行查询的环境中,并提供最好的性能。大多数人都说它是Join的重型升降机。
Nested Loop Join
Nested Loop Join是为那些有索引的小表或其中人一个有索引的大表。它对那些小表连接,需要循环执行从一个到另一个表的按行比较的情况下工作最好的。
我希望你现在能理解查询优化器是如何选择最优的查询类型。
原文地址:Merge join Vs Hash join Vs Nested loop join
分享到:
相关推荐
数据库中JOIN操作的实现主要有三种:嵌套循环连接(Nested Loop Join),归并连接(Merge Join)和散列连接或者哈稀连接(Hash Join)。其中嵌套循环连接又视情况又有两种变形:块嵌套循环连接和索引嵌套循环连接。
在对传统的Sort-Merge-Join算法进一步研究的基础上,提出了一种改进的闪存数据库Sort-Merge-Join算法。该算法只对小关系进行外...通过理论分析和与传统Sort-Merge-Join算法在闪存上的比较实验,证明了该算法的优越性。
数据库 我自己在 Java 中实现了 SortMergeJoin 和 HashJoin(来自 SQL 的著名 INNER JOIN)。 在更多信息。
Sql中的三种物理连接操作 嵌套循环连接(Nested Loop Join) 合并连接(Merge Join) 哈希匹配(Hash Join)
NULL 博文链接:https://forlan.iteye.com/blog/2245814
hash join/merge join/nest loop(cluster join)/index join 2:不借助第三方工具,怎样查看sql的执行计划 set autot on explain plan set statement_id = &item_id for &sql; select * from table(dbms_...
merge 比较工具 merge 比较工具merge 比较工具
Oracle的三种表连接方式 详细讲述• sort merge join(SMJ) • nest loop(NL) • hash join(HJ)
WinMerge文件比较工具,WinMerge文件比较工具
sql学习 Merge Sort Join优化第4式(保证PGA尺寸).sql
类似beyond compare的对比工具,很实用,无需烦人的注册码。
sql学习 Merge Sort Join优化第2式(连接条件索引消除排序).sql
在这里,将接着介绍pandas中也常常用到的join 和merge方法 merge pandas的merge方法提供了一种类似于SQL的内存链接操作,官网文档提到它的性能会比其他开源语言的数据操作(例如R)要高效。 和SQL语句的对比可以看...
Araxis Merge是一款比对软件工具,不仅支持单个文件的比对,而且支持对两个文件夹的所有文件进行对比,并实时修改。用了蛮久感觉很好用,所以分享给大家。 里面给大家内嵌了Araxis Merge v6.5和Araxis Merge 2017两...
sql学习 Merge Sort Join优化第1式(两表限制条件有索引).sql
快速浏览一、append与... update方法(a)三个特点(b)例子三、concat方法四、merge与join1.merge函数2. join函数五、问题与练习阶段总结Reference #从清华镜像拉装1.0.3版本的Pandas !pip install -i https://pypi.t
Pandas合并DataFrame_Merge,_Join,_Concat,_Append【Pandas入门教程6】
sql学习 Merge Sort Join优化第3式(避免取多余列致排序尺寸过大).sql
merge 比较工具merge 比较工具merge 比较工具merge 比较工具merge 比较工具merge 比较工具merge 比较工具merge 比较工具
WinMerge文件对比软件