SQL Server三种表链接原理

 

  在SQL Server数据库中,查询优化器在处理表链接时,一般会使用一下三种链接方式:html

      • 嵌套循环链接(Nested Loop Join)
      • 合并链接 (Merge Join)
      • Hash链接 (Hash Join)

  充分理解这三种表链接工做原理,可使咱们在优化SQL Server链接方面的代码有据可依,为开展优化工做提供必定的思路。接下来咱们来认识下这三种链接。算法

1. 嵌套循环链接(Nested Loop Join)数据库

  该链接方式一般在小数据量而且语句比较简单的场景中使用,也是比较常见的链接方式,好比如下示例:数组

   1:  use AdventureWorks2008 
   2:  go 
   3:  SELECT H.* 
   4:  FROM Sales.SalesOrderHeader H 
   5:  JOIN Sales.Sale
 1: use AdventureWorks2008 
sOrderDetail D
   6:  ON H.SalesOrderID=D.SalesOrderID 
   7:  WHERE H.SalesOrderID = 43659 

  AdventureWorks2008数据库是SQL Server的一个sample,你能够在微软官方网站上自由下载。http://msftdbprodsamples.codeplex.com/releases/view/37109安全

  咱们在数据库中运行这段代码:数据结构

clip_image002

  经过执行计划咱们能够看到,数据库的优化器使用了嵌套链接(Neasted Loops),上面第一行中的Sales.SalesOrderHeader表由于只有一行数据因此作为外部表使用,SalesOrderDetail有12行数据作为内部表使用。并发

  嵌套循环的工做原理如图所示:函数

clip_image004

图1 嵌套循环工做原理图oop

  其原理就是根据条件从表中过滤出一个外部连接表,循环的从外部表中读取一行数据,去内部表中进行匹配,伪码以下:性能

For (i=0;i< Number of outerTable Row;i++)

{

    OuterTable[i] connect InnerTable[1,2.....N] To Create New Row

    WHERE OuterTable[i].data.value = OuterTable[1,2.....N].data.Value

}

  了解嵌套的工做原理后,咱们不难发现,这种链接的方式具备必定的局限性的:

1. 由于算法是循环进行的,因此比较适合数据量较小的表进行链接,尤为是外部表的数据。

2. 两张表最好是排序的。表中的条件列和链接列最好有索引,尤为是内部表必须有索引,这样工做效率会成倍增长。

当外部表较小,而内部表较大而且链接字段上有索引的状况下,循环嵌套很是高效。而且嵌套循环是三种方式中惟一支持不等式链接的方式。

2. 合并链接 (Merge Join)

  在SQL Server数据库中,若是查询优化器,发现要链接的两张对象表,在链接列上都已经排序并包含索引,那么优化器将会极大可能选择“合并”链接策略。条件是:两个表都是排序的,而且表链接条件中至少有一个等号链接,查询分析器会去选择合并链接。

  代码示例:

   1:  USE AdventureWorks2008 
   2:   
   3:  GO 
   4:   
   5:  SELECT P.* 
   6:   
   7:  FROM Production.ProductModel P 
   8:   
   9:  JOIN Production.ProductModelProductDescriptionCulture PPMD 
  10:   
  11:  ON P.ProductModelID = PPMD.ProductModelID 

  根据执行计划咱们能够看到,此次的链接操做使用的合并链接:

clip_image006

  这两张表中,数据量分别为128和762行数据,链接列是表中的主键而且数据是有序的,所以数据库的查询优化器自动选择了合并链接。合并链接的工做原理以下图所示:

合并链接原理

图2 合并链接的工做原理

  数据库优化器在决定使用合并链接后,并行的在两个表(术语叫输入集合)中各取第一行数据,进行匹配,匹配则返回匹配行并进行链接。若是不匹配,那么小的那一个表(输入集合),则顺序取下一行数据继续尝试匹配。

  经过其工做原理咱们能够发现,合并链接能够当作是一个相似于并发工做机制。操做分别在两个表(输入集合)依次获取数据并进行比较,这就要求两张表是有序的,有序的排列会极大的提升工做的效率。

  有关表排序的问题,若是链接语句中使用Sort关键字来排序数据表,那么SQL Server的优化器会比较倾向于Hash Join。在合并链接中,并不排斥order by, group by, distinct等关键字,在使用这些语句时,查询优化器也有极大的可能选择合并链接。

  当咱们使用一些查询限定条件,好比不等式(>,<,>=等)限定条件范围,那么合并链接的效率会有更好。

  合并链接的限定条件:

1. 两张表的链接列须要排序

2. 链接列必须有索引

3. 哈希链接(Hash Join)

  当咱们尝试将两张数据量较大,没有排序和索引的两张表进行链接时,SQL Server的查询优化器会尝试使用Hash Join。

代码示例:

   1:  SELECT * 
   2:   
   3:  FROM Production.Product P 
   4:   
   5:  Join Production.ProductSubcategory SPC 
   6:   
   7:  on P.ProductSubcategoryID = SPC.ProductSubcategoryID 

  根据执行计划咱们能够看到,此次的链接操做使用的哈希链接:

clip_image010

  该链接在处理大量无序的数据时,效率较高,可是对处理器和内存资源的消耗较大。实现过程以下:

  Hash Join链接的执行操做分为两个阶段,创建和探测。

  创建是指对输入表进行的一系列的操做。首先优化器会将输入表中的每一行数据扫描到系统内存中,而后根据内置的散列算法计算出相应散列值,相同散列值的数据会被分到一个Hash池中。这些散列值和数据地址保存在一个Hash表中,提供给探测使用。一般优化器会选择数据较少的表做为创建输入表。

  创建完成后,开始探查工做。另外一个链接表(咱们叫探查输入)一样会被逐行的扫描、计算,得出一个Hash值。链接操做会使用探查输入的Hash值和创建输入的Hash值列表进行扫描和匹配工做,最终创建链接。

clip_image012

  上图是Hash链接的工做流程,接下来咱们能够来了解下哈希算法的实现的机制,如下的内容是我的对算法的理解,如有偏颇请指正。

  Hash的实际含义是“散列”的意思,它主要的功能就是将一组数据,经过算法,变换成固定长度的输出,这个输出咱们就称之为散列值(Hash值),一般在安全领域,如密码学中使用较多。

  在SQL Server里面哈希散列函数是黑盒的,没有具体的算法能够参考。实际上不少开发人员在解决海量数据查询的时候,都会采用Hash方式,而且开发适合需求的散列算法。经常使用的一些算法包括一些取余、MD二、MD四、MD5 和 SHA-1等等。

  由于算法,不一样的数据可能会生成相同的散列值。它将大量的数据按照规则分散到不一样数据堆或者链表中,创建内部的映射关系。咱们能够认为他是将数组和链表结合在一块儿,想要达到一种寻址容易、插入删除方便的数据结构,而Hash表就是一种数据内容和数据存放地址之间的映射关系。

  散列函数的选择会决定影响Hash表元数量大小和每一个键值包含的数据多少,这个是数学上的问题这里不进行进一步讨论。

  说到这里,可能你们仍是不太理解,咱们这里举例来讲明:

  好比说有两张表:

表A{A,F,C,D,B,E……}

表B{F,B,E,D,A,F…….}

  而且表A的数据量小于表B,这两张表进行Hash链接的过程以下:

Hash链接原理2

1. 首先数据库会将表A中的全部数据,扫描存入内存中。

2. 内存中的表A的数据,通过散列函数依次获得对应的散列值(Hash值)。

3. 表A中相同散列值(键值)的数据,会统一的放入到一个Hash池中。我的认为Hash池中的数据,就是数组和链表的集合。Hash的键值能够看到是一个数组的下标,而池中的数据以链表的形式链接在数组中。

Hash【键值】-->数据1-->数据2..............

如图中的一组数据,数据A和数据C具备相同的Hash值,值为001,那么他们都被分配到以001命名的Hash池中。

4. 将Hash值和对应的数据,依次存入到一个Hash表中,创建结束。

5. 探测阶段,数据库依次读取扫描表B中的每一行数据,并经过散列函数计算出一个Hash值。

6. 根据Hash值,去Hash表中和表A的键值进行匹配,找到对应的Hash池。

7. 接下来将表B的数据去和对应的Hash池中的每条数据,去对比和匹配。若是匹配成功则进行数据链接。

  经过对原理的了解,咱们能够看到这种链接方式,须要大量的计算操做,对CPU带来必定的压力。一般Hash 链接操做在内存中进行,若是内存不足,数据库会将数据写入到硬盘中,影响性能。

    4.小结

三种链接方式的特色:

类型

链接列上索引

表的大小

排序

链接子句

嵌套

内部表:必须

外部表:有最好

可选

全部类型

合并

内部表:必须 聚簇索引或者覆盖索引

外部表:必须 聚簇索引或者覆盖索引

须要

Equi-join

HASH

内部表:不须要

外部表:可选,最好有

小的外部表,大得内部表

任意

不须要

Equi-join

三种方式对资源的压力:

 

嵌套循环链接

合并链接

哈希链接

CPU

低(若是没有显式排序)

内存

低(若是没有显式排序)

IO

可能高可能低

可能高可能低

  以上是我的对三种链接的我的理解,不当之处请指正。

题外话:

  其实咱们能够把这三种链接比喻成相亲。

  嵌套链接就是熟人介绍,亲戚朋友根据你的条件,搜索下周围的资源,而后安排你和几个姑娘见面,看看能不能匹配上。若是你的条件很明确(外部表索引),而且朋友对姑娘比较熟悉,对方的要求也很明确(内部表索引),那么成功率就会比较高。

  合并链接就是社区或者网站组织的小型相亲联谊会,好比电影《恋爱33天中》那种8分钟面对面的形式。男女双方面对面进行交谈(匹配判断),每几分钟就换一我的再次交谈,因为你们条件和目的性明确(都有索引),因此整个流程效率会比较高。

    Hash链接则就像是万人相亲大会,好比上海的中山公园(条件好的已婚人士慎入)。单身青年的父母,入园后因为各类缘由随机的分红各个小群组(通过散列函数分红Hash池)。而后参与者根据本身的判断(确认Hash键值),找到合适小组后(Hash键值相等),依次交谈交换条件和信息(尝试匹配),看看里面有没有合适人选,有就进一步了解(匹配成功,链接)。

2013年11月14日 Ralf Wang

相关文章
相关标签/搜索