详解索引连接类型

原文:详解索引连接类型

  SQL Server有3种连接类型:

  • Hash连接;
  • 合并连接;
  • 嵌套循环连接;

  在许多影响小的行集的简单查询中,嵌套循环连接远远优于hash和合并连接。用于查询的连接类型由优化器动态决定。

  下面我来先来建立两张简单的表。Province(十条数据)=》PersonTenThousand(1万数据),省份和人的关系,一对多,外键相连;

一、Hash连接

  为了理解哈希连接,在这个连接中PersonTenThousand在连接列PId上没有任何索引,先来看看如下查询:

  

  可以看到,优化器在两个表之间使用了Hash连接。这种情况经常出现于下表(大表)较大,并且下表(大表)的连接列上没有索引。

  Hash连接使用两个连接输入-建立输入和探查输入。建立输入是执行计划中上面的那个输入(小表),探查输入是下面那个输入(大表)。两个输入中较小的一个作为建立输入。

  Hash连接的执行分为两个阶段:建立阶段和探查阶段。在最常用的Hash连接方式-内存中的Hash连接中,整个建立输入被扫描或计算,然后再内存中建立一个Hash表。每个行根据计算的Hash键值(相当于断言中的一组列)被插入到一个Hash表元中。

  这个建立阶段之后是探查阶段。整个探查输入被逐行进行扫描或计算,对于每个探查行,计算一个Hash键值。对应的Hash表元使用来自探查输入的Hash键值进行扫描,匹配被生成。

  查询优化器使用Hash连接高效处理大的、未排序、没有索引的输入。通常:所求数据在其中一方或双方没有排序的条件达成时,会选用哈希匹配。

二、合并连接

  先看下面的查询:

  

  对于这个查询,优化器使用两个表之间的一个合并连接。合并连接要求两个连接输入在合并列上排序,这将在连接条件中定义。如果两个连接上有索引,那么连接输入由该索引排序。因为每个连接输入都被排序,合并排序从每个输入得到一行比较是否相等,如果它们相等,匹配的行被生成。这个过程重复道所有行都被处理。

三、嵌套循环

  在以上的查询中,下面我们将在PersonTenThousand表的PId(连接列)上建立聚集索引,在运行相同的查询:

  

  嵌套循环连接使用一个连接输入作为外部输入表,另一个作为内部输入表。外部输入表是执行计划中上面的输入,而内部输入表是下面的输入表。外部循环逐行消费外部输入表。内部循环为每个外部行执行一次,搜索内部输入表的匹配行。

  如果外部输入相当小,内部输入大但是有索引,嵌套循环连接是非常高效的。在许多影响少数行的简单查询中,嵌套循环连接远远优于Hash和合并连接。连接通过牺牲其他方面来提高速度-使用内存来取得小的数据集并且快速地与第二个数据集比较,循环连接熟读很快。合并连接与此相似,使用内存和一小部分tempdb来进行其排序的比较,Hash连接使用内存和tempdb建立hash表。虽然循环连接更快,但是随着数据集变得更大,它比Hash或合并消耗更多的内存,这就是SQL Server在不同数据集的情况下使用不通计划的原因。

连接类型 连接列上的索引 连接表的一般大小 预先排序 连接子句
Hash
内部表:不需要索引

外部表:可选

最佳条件:小的外部表,大的内部表

任意 不需要 Equi-join
合并
内部/外部表:必须有索引

最佳条件:两个表都有聚集或覆盖索引

需要 Equi-join
嵌套循环
内部:必须索引

外部:最好有索引

可选 所有

   要注意排序条件。上面的表格总结的已经非常好了,要不是说最佳条件覆盖索引,我到现在都搞不出合并连接的示例。

 

时间: 2025-01-27 03:31:55

详解索引连接类型的相关文章

详解Swift的类型检查器

本文讲的是详解Swift的类型检查器, 这篇文章将围绕曾不断使我重写代码的一些 Swift 编译器的报错信息展开: 错误:你的表达式太过于复杂,请将其分解为一些更为简单的表达式.(译者注:原文是error: expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions) 我会看那个触发错误的例子,谈谈以后由相

【Redis缓存机制】详解Java连接Redis_Jedis_事务_java

Jedis事务 我们使用JDBC连接Mysql的时候,每次执行sql语句之前,都需要开启事务:在MyBatis中,也需要使用openSession()来获取session事务对象,来进行sql执行.查询等操作.当我们对数据库的操作结束的时候,是事务对象负责关闭数据库连接. 事务对象用于管理.执行各种数据库操作的动作.它能够开启和关闭数据库连接,执行sql语句,回滚错误的操作. 我们的Redis也有事务管理对象,其位于redis.clients.jedis.Transaction下. Jedis事

详解JDBC连接Access的三种方法

JDBC连接Access第一种方法: 你用下面的代码试试 (强烈建议也是only可以建议的方法) con = DriverManager.getConnection("jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ=C:/data/Access/test1.mdb","dba","sql"); 后面的代码一样.这样你就可以访问access数据库了. JDBC连接Access第二种方法:

普通型母函数详解及其模板类型

PS:还记得第一次接触普通型母函数(也就是生成函数)还是在离散数学的课本上,当时也不太会敲代码,仅限于能够手动计算,现在就要详细的介绍一下关于母函数的内容了: 普通型母函数又叫生成函数, 1.定义:设G(x) = a0 + a1*x + a2*x^2 + ... + an*x^n + ...,就称G(x) 是序列{an}的生成函数: Eg:{C(n,m)}的生成函数是 (1+x)^m,{k^n}的生成函数是 G(x) = 1+k*x+k^2*x^2+.. == 1/(1-k*x) 2.基本模型:

详解远程连接Mysql数据库的问题(ERROR 2003 (HY000))_Mysql

在我们用客户端及其远程连接服务器Mysql数据库的过程中,容易出现下面问题: 问题代码代码 ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.0.19' (111)  ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.0.19' (111)      这个 原因就是Mysql数据库的默认配置文件my.cnf(linux下)中的bind-address

防火墙术语详解之防火墙类型

目前市场的防火墙产品非常之多,划分的标准也比较杂. 主要分类如下: 1. 从软.硬件形式上分为 软件防火墙和硬件防火墙以及芯片级防火墙. 2. 从防火墙技术分为 "包过滤型"和"应用代理型"两大类. 3. 从防火墙结构分为 单一主机防火墙.路由器集成式防火墙和分布式防火墙三种. 4. 按防火墙的应用部署位置分为 边界防火墙.个人防火墙和混合防火墙三大类. 5. 按防火墙性能分为 百兆级防火墙和千兆级防火墙两类.

JDBC 连接MySQL实例详解_Mysql

JDBC连接MySQL JDBC连接MySQL 加载及注册JDBC驱动程序 Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver").newInstance(); JDBC URL 定义驱动程序与数据源之间的连接 标准语法: <protocol(主要通讯协议)>:<subprotocol(次要通讯协议,即驱动程序名称)>:<data so

TIMESTAMP列类型详解(怎样设列的默认值为Now())

详解 TIMESTAMP列类型详解(怎样设列的默认值为Now()) MySQL目前不支持列的Default 为函数的形式,如达到你某列的默认值为当前更新日期与时间的功能,你可以使用TIMESTAMP列类型下面就详细说明TIMESTAMP列类型 TIMESTAMP列类型TIMESTAMP值可以从1970的某时的开始一直到2037年,精度为一秒,其值作为数字显示.TIMESTAMP值显示尺寸的格式如下表所示::+---------------+----------------+| 列类型      

WinForm控件开发总结(六) 控件属性类型转换器代码详解

在上一篇文章,我为控件添加一个一个复杂属性,并且为这个属性的类型的编写了一个类型转换器, 现在我们来看看这个类型转换器的代码,并解释一下这些代码的意义. 要实现一个类型转换器,我们必须要重写(override)四个方法: CanConvertFrom()――根据类型参数进行测试,判断是否能从这个类型转换成当前类型,在本例中我 们只提供转换string和InstanceDescriptor类型的能力. CanConvertTo()――根据类型参数进行测试,判断是否能从当前类型转换成指定的类型. C