表关联:Hash、Nested Loops、Merge。这是实际算法,不是T-SQL中的inner/left/right/full/cross join。优化器会把这些T-SQL写法转换成上面的3种算法。

通过这3种算法,可以推出其他操作符的行为。

1.Hash Match Join

Hashing(散列法)和Hash Table。

Hashing:是编码技术,把数据转换成符号格式,以便有效的支持数据查询。如SQL Server会把一行数据转换成一个能标识这行数据内容的唯一值,并存放到一个表中,这个表就是Hash Table,也就是哈希表,这种技术类似加密,当需要原始数据时,也能解密出来。

Hash Table:实际上是一个数据结构,通过散列法的处理,把数据存放到表中,如SQL Server从一个实体表中查询数据,并把数据转成哈希值,存放到一个哈希表中,这个表则存放在tempdb中。

当SQL Server 把两个数据放入临时的哈希表中,然后用这个结构对比数据,并返回匹配的数据时,就会出现Hash Match操作符。

select e.JobTitle,a.City,p.LastName+','+ p.FirstName as EmployeeName
from HumanResources.Employee as e
join Person.BusinessEntityAddress as bea
on e.BusinessEntityID=bea.BusinessEntityID
join Person.Address a
on bea.AddressID=a.AddressID
join Person.Person as p
on e.BusinessEntityID =p.BusinessEntityID

  

这个Hash Match Join操作把Index Scan和Nested Loops合并,然后输出结果集,这个操作符是开销比较大的操作符,在性能优化中也应该纳入检查范畴。看看tooltips

当SQL Server必须关联两个大数据集时,会把两个数据集中较小那个集合的数据进行散列处理,把哈希值存入tempdb的哈希表上,然后较大的那个数据集,会一行一行的与哈希表匹配,以便实现‘关联’逻辑,由于较小的表已经被转换成哈希表,所以它的体积会变得更小,在对比时使用哈希值相对较快。所以如果哈希表比较小,处理速度将会更快。如果两表都很大,对比于其他类型的关联算法,Hash Match Join会非常低效。同时,由于Hash表中存放在tempdb中,所以查询中的Hash Join将会给tempdb带来很大的负载压力。

当看到Hash Match时,应该检查一下是否存在下面的问题:

丢失索引或者无效索引

缺少Where条件

where条件中存在非SARG操作,如对筛选列进行标量函数、隐式类型转换等,

以上会导致优化器不使用上面已由的索引。

Hash Match暗示着你可能需要检查查询是否有改写可能,是否可以加索引,使其关联时更加有效,如果没有可能,Hash Match Join也不失为一个高效的算法。

2.Nested Loops Join

上面的执行计划右边第一个是Nested Loops操作符。表Employee和表BusinessEntityAddress上分别存在聚集索引扫描和聚集索引查找,连个操作通过箭头汇总到Nested Loops操作符中

Nested Loops Join涉及两个数据集,一个叫做inner set,一个叫做outer set,位于上方的是outer set,下方的为inner set。这种算法把inner set的数据集与outer set一一匹配,知道inner set的数据集全部扫描完毕为止。如果两个数据集都很小,或者inner set数据很小,这种算法可算是最佳关联算法。

3.Merge Join

它的特点:关联的数据已经排序。这种算法把两个数据集合并到一起,由于已经预先排序,所以数据合并后已是有序的。然后会和匹配值匹配,排序的数据可以很快地标识数据,如1,2,3这样的数据,如果匹配到数据2已经找到,就不需要在往后查找了。

对于已经排序的数据集,这种算法是其中一种最高效的算法,但是很多时候数据集都是无序的,所以这种算法会引入一个排序操作符来协助工作,这个操作符会降低预期的

 select c.CustomerID from Sales.SalesOrderDetail od
join Sales.SalesOrderHeader oh on od.SalesOrderID=oh.SalesOrderID
join Sales.Customer c on oh.CurrencyRateID=c.CustomerID

  

由于没有Where条件,SalesOrderHeader和Customer会进行相应的扫描操作。得到的数据集会通过Merge Join关联,当关联列已排序时,优化器会考虑用这种算法。关联使用了CustomerID作为两表关联关系,而这个列在两表中均有索引,也就是预排序。

这种算法对预排序的关联列非常高效。反之,如果关联列没有预排序,优化器又选择了这种算法,就会出现以下两种情况:

1.优化器预先排序关联列,然后在进行Merge Join

2. 使用较为低效的Hash Match关联

四.筛选数据

 select e.JobTitle,a.City,p.LastName+', '+p.FirstName as EmployeeName
from HumanResources.Employee as e
join Person.BusinessEntityAddress as bea on e.BusinessEntityID=bea.BusinessEntityID
join Person.Address a on bea.AddressID=a.AddressID
join Person.Person as p on e.BusinessEntityID=p.BusinessEntityID
where e.[JobTitle]='Production Technicaian - WC20'

  

右上角的聚集索引扫描,WHERE条件使用PK_Employee_BusinesEntityID把数据集控制到了22行,由于数据量很小,优化器决定使用Nested Loops算法关联两表,产生数据集

聚集索引扫面的影响函数:

嵌套循环后的影响行数:

可以看到数据量还是很少,下一步优化器会用这个结果集和Address上通过聚集索引查找获得的数据再次进行Nested Loops。由于查询中添加了where子句,所以把数据控制到了很小的程度。把where条件去掉,再看之心计划,从中可以看到添加条件的重要性。

使用SET STATISTICS TIME ON 和SET STATISTICS IO ON查询。然后分别执行,查看数值,当然,前提是返回结果是一致的,不一致的数据没什么可比性。还有,就是把两个查询放到一个查询界面,然后打开实际执行计划,运行查询,再从执行计划中对比两者的开销,通常来说,百分比越低,开销越小,理论上性能也就越好。

SQL Server表关联的更多相关文章

  1. SQL Server表分区【转】

    转自:http://www.cnblogs.com/knowledgesea/p/3696912.html SQL Server表分区   什么是表分区 一般情况下,我们建立数据库表时,表数据都存放在 ...

  2. SQL Server表分区详解

    原文:SQL Server表分区详解 什么是表分区 一般情况下,我们建立数据库表时,表数据都存放在一个文件里. 但是如果是分区表的话,表数据就会按照你指定的规则分放到不同的文件里,把一个大的数据文件拆 ...

  3. SQL Server表分区-水平分区

    SQL Server表分区,sql server水平分区 转自:http://www.cnblogs.com/knowledgesea/p/3696912.html  根据时间的,直接上T-SQL代码 ...

  4. 在一个SQL Server表中的多个列找出最大值

    在一个SQL Server表中一行的多个列找出最大值 有时候我们需要从多个相同的列里(这些列的数据类型相同)找出最大的那个值,并显示 这里给出一个例子 IF (OBJECT_ID('tempdb..# ...

  5. SQL Server表分区的NULL值问题

    SQL Server表分区的NULL值问题 SQL Server表分区只支持range分区这一种类型,但是本人觉得已经够用了 虽然MySQL支持四种分区类型:RANGE分区.LIST分区.HASH分区 ...

  6. SQL Server 表变量和临时表的区别

    SQL Server 表变量和临时表的区别 一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯 ...

  7. [转载]在SQL Server 中,如何实现DBF文件和SQL Server表之间的导入或者导出?

    原来使用SQL Server 2000数据库,通过DTS工具很方便地在SQL Server和DBF文件之间进行数据的导入和导出,现在安装了SQL Server2005之后,发现其提供的“SQL Ser ...

  8. SQL server 表中如何创建索引?

    SQL server 表中如何创建索引?看个示例,你就会了 use master goif db_id(N'zhangxu')is not nulldrop database zhangxugocre ...

  9. 图解SQL多表关联查询

      图解SQL多表关联查询     网上看了篇文章关于多表连接的,感觉很好,记录下来,以便日后自己学习  内连接     左连接     右连接       全外连接   1. 查两表关联列相等的数据 ...

随机推荐

  1. JiBX笔记

    注意事项 JiBX:1.2.2 (https://sourceforge.net/projects/jibx/files/jibx/jibx-1.2.2/) JDK:1.6 (http://www.o ...

  2. html5离线记事本

    离线记事本 这是一个笔记应用,不需要联网,也不需要数据库,可以直接把数据储存在本地.方便易用! ^_^ <!DOCTYPE html>  <html>  <head> ...

  3. pt-table-checksum 使用方法【转】

    27. pt-table-checksum27.1 pt-table-checksum 作用 主要用来检查主从数据是否一致,原理即在主库执行把表每行的列通过concat函数进行拼接,然后对拼接的值进行 ...

  4. python3+selenium框架设计09-生成测试报告

    使用HTMLTestRunner可以生成测试报告.HTMLTestRunner是unittest模块下的一个拓展,原生的生成报告样式比较丑,GitHub上有大佬优化过后的版本:GitHub地址.下载之 ...

  5. zTree:一个依靠 jQuery 实现的多功能 “树插件”

    官方网站: http://www.treejs.cn/v3/main.php#_zTreeInfo 使用方式: 步骤1.文件准备 将需要使用的 zTree v3.x 相关的 js.css.img 文件 ...

  6. K-query SPOJ - KQUERY 离线 线段树/树状数组 区间大于K的个数

    题意: 给一个数列,一些询问,问你区间$[l.r]$大于$K$的个数 题解: 又一个"人尽皆知傻逼题"? 我们用一个01序列表示当前询问时,该位置的数字是否对答案有贡献, 显然,对 ...

  7. Spring MVC全局异常处理

    继承HandlerExceptionResolver接口实现自己的处理方法,如: public class MyHandlerExceptionResolver implements HandlerE ...

  8. 035_lua快速入门

    执行下面的脚本用luajit test.lua即可 一.变量及逻辑运算 --number, string, boolean, table, function, thread, userdata, ni ...

  9. 010_mac常用docker维护命令

    一. ➜ ~ docker search rabbitmq #搜索 NAME DESCRIPTION STARS OFFICIAL AUTOMATED rabbitmq RabbitMQ is an ...

  10. ansible笔记(10):初识ansible playbook

    ansible笔记():初识ansible playbook 假设,我们想要在test70主机上安装nginx并启动,我们可以在ansible主机中执行如下3条命令 ansible test70 -m ...