从很多网页上都看到,SQL Server有三种Join的算法, nested loop join, merge join, hash join. 其中最常用的就是nested loop join.

在介绍nested loop join的很多文章里,都提到如果两个表做nested loop join,取行数较小的表作为外循环表,行数较多的表作为内循环表, join的效率会比较高.

其中之一的原因是如果内循环表做join的列上有合适的索引的话,那么外循环的每一条输入数据可以做索引的seek,这样就不会把整个的内循环表读一遍,尤其是内循环表比较大的话,节省的成本更高. 但是如果内外循环表都没有合适的索引,这样做join,为什么效率也比较高呢?

举个例子,外循环表有10行数据,内循环表有1000行数据,按照nested loop join 的算法,外循环表中取一条,和内循环表的所有数据匹配一遍,输出匹配的数据行. 这样就是要进行10*1000=10000次的匹配; 如果反过来,外循环1000行,内循环10行,那么外循环表中取一条数据,内循环表中遍历10行数据,总计也是1000*10=10000次. 粗看来都一样啊..为什么都说外循环表小的话,效率高呢?  做个试验看看吧.

use tempdb
go
--创建两个表,测试nested loop join的效率
CREATE TABLE TempA (string VARCHAR(1000))
go
CREATE TABLE TempB (string VARCHAR(1000))
go
--插入数据, 让表TempA中的数据刚好存在1页里
INSERT INTO TempA SELECT REPLICATE('a' , 1000)
INSERT INTO TempA SELECT REPLICATE('b' , 1000)
INSERT INTO TempA SELECT REPLICATE('c' , 1000)
INSERT INTO TempA SELECT REPLICATE('d' , 1000)
INSERT INTO TempA SELECT REPLICATE('e' , 1000)
INSERT INTO TempA SELECT REPLICATE('f' , 1000)
INSERT INTO TempA SELECT REPLICATE('g' , 1000)

--往TempB中插入数据,让TempB的数据是TempA的100倍
insert into TempB select * from TempA
go 100
--检验一下表TempA 和 TempB的大小
set statistics io on
select * from TempA
select * from TempB
--返回的结果如下:
/*
Table'TempA'. Scan count 1, logical reads 1
Table'TempB'. Scan count 1, logical reads 100
*/
--由此可以看出表TempA有7行,存储在1个页; TempB有700行,存储在100个页里.

--执行以下查询,将TempA作为外循环表,TempB作为内循环表,看看执行的成本如何
SELECT *FROM TempA a INNER LOOP JOIN TempB b
ONa.string = b.string OPTION (FORCE order)
/*
Table'TempB'. Scan count 1, logical reads 700
Table'TempA'. Scan count 1, logical reads 1
*/

从结果可以看出从TempA读了1个页,从TempB读了700个页,合计701个逻辑读, 也就是说外循环的表,做一次全表读,有多少页就有多少逻辑读; 内循环的表,对应外循环表的每1条记录,都要读一次全表读,即7乘以100,700个逻辑读.

如果按照这个规律,调换内外循环表的位置,得到的逻辑读应该是 TempB的一次全表读, 100个逻辑读加上700行乘以TempA的全表读(1页),就是700个逻辑读,合计是800个逻辑读.

--对调一下join的顺序,再看看执行成本:
SELECT *FROM tempb b INNER LOOP JOIN tempa a
ONa.string = b.string OPTION(FORCE ORDER)
/*
Table'TempA'. Scan count 1, logical reads 700
Table'TempB'. Scan count 1, logical reads 100
*/

果不其然,和预计的一样.

所以在这种假定的情况下,外循环表较小的话,join的成本更低.

实验的表结构比较特殊,如果往一般情况推演一下,可以做出这样的假设:

假设表X有a页,平均每页有b行,表Y有c页,平均每页有d行.
则以表X为外循环,表Y为内循环,则nested loop join的成本是 a+(a*b*c), 而已表Y为外循环,表X为内循环,则nested loop join的成本是 c+(c*d*a)

SQL Server nested loop join 效率试验的更多相关文章

  1. 浅谈SQL Server中的三种物理连接操作(Nested Loop Join、Merge Join、Hash Join)

    简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...

  2. Merge join、Hash join、Nested loop join对比分析

    简介 我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge Join,Hash Join ...

  3. Oracle 表的连接方式(1)-----Nested loop join和 Sort merge join

    关系数据库技术的精髓就是通过关系表进行规范化的数据存储,并通过各种表连接技术和各种类型的索引技术来进行信息的检索和处理. 表的三种关联方式: nested loop:从A表抽一条记录,遍历B表查找匹配 ...

  4. join中级篇---------hash join & merge join & nested loop Join

    嵌套循环连接(Nested Loop Join) 循环嵌套连接是最基本的连接,正如其名所示那样,需要进行循环嵌套,嵌套循环是三种方式中唯一支持不等式连接的方式,这种连接方式的过程可以简单的用下图展示: ...

  5. 三大表连接方式详解之Nested loop join和 Sort merge join

    在早期版本,Oracle提供的是nested-loop join,两表连接就相当于二重循环,假定两表分别有m行和n行       如果内循环是全表扫描,时间复杂度就是O(m*n)       如果内循 ...

  6. 44 答疑(三)--join的写法/Simple nested loop join的性能问题/Distinct和group by的性能/备库自增主键问题

    44 答疑(三) Join的写法 35节介绍了join执行顺序,加了straight_join,两个问题: --1 如果用left join,左边的表一定是驱动表吗 --2 如果两个表的join包含多 ...

  7. 禁用nested loop join里的spool

    禁用nested loop join里的spool 转载自: https://blogs.msdn.microsoft.com/psssql/2015/12/15/spool-operator-and ...

  8. 1122MySQL性能优化之 Nested Loop Join和Block Nested-Loop Join(BNL)

    转自http://blog.itpub.net/22664653/viewspace-1692317/ 一 介绍  相信许多开发/DBA在使用MySQL的过程中,对于MySQL处理多表关联的方式或者说 ...

  9. SQL Server中INNER JOIN与子查询IN的性能测试

    这个月碰到几个人问我关于"SQL SERVER中INNER JOIN 与 IN两种写法的性能孰优孰劣?"这个问题.其实这个概括起来就是SQL Server中INNER JOIN与子 ...

随机推荐

  1. rabbitmq安装.教程

    https://www.cnblogs.com/ericli-ericli/p/5902270.html (rabbitmq安装)https://www.cnblogs.com/iiwen/p/538 ...

  2. android模拟器不能上网设置

    进行sdk目录中的platform-tools目录: adb devices 系统会罗列出所有设置 adb -s emulator- shell 最后设置网关 setprop net.dns1 192 ...

  3. Python : locals and globals

    Python有两个内置的函数,locals() 和globals(),它们提供了基于字典的访问局部和全局变量的方式.Python使用叫做名字空间的东西来记录变量的轨迹.名字空间只是一个 字典,它的键字 ...

  4. js 正则表达式,匹配邮箱/手机号/用户名

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. 744. Find Smallest Letter Greater Than Target

    俩方法都是用二分查找,一个调库,一个自己写而已. 方法一,调库 static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NUL ...

  6. 693. Binary Number with Alternating Bits

    static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...

  7. 2019.01.10 bzoj1095: [ZJOI2007]Hide 捉迷藏(动态点分治)

    传送门 蒟蒻真正意义上做的第一道动态点分治! 题意:给一棵最开始所有点都是黑点的树,支持把点的颜色变成从黑/白色变成白/黑色,问当前状态树上两个最远黑点的距离. 思路: 首先考虑不带修改一次点分治怎么 ...

  8. UVa 11021 Tribles (概率DP + 组合数学)

    题意:有 k 只小鸟,每只都只能活一天,但是每只都可以生出一些新的小鸟,生出 i 个小鸟的概率是 Pi,问你 m 天所有的小鸟都死亡的概率是多少. 析:先考虑只有一只小鸟,dp[i] 表示 i 天全部 ...

  9. jq,ajax,post例子。

    jq post 例子 <script> $(function(){ $('#button').on('click', function(){ $.ajax({ type: 'POST', ...

  10. nginx搭建简单的图片服务器

    传统项目一般实现图片上传的话,都会在tomcat下面建立一个图片文件夹,上传成功后,用户可以直接访问, http://ip:port/project/images/xxx.jpg; 这样在用户量少的时 ...