SQL Server 2005 hash联接算法

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介: 如果两个联接输入都很大,而且这两个输入的大小差不多,则预先排序的合并联接提供的性能与哈希联接相近。但是,如果这两个输入的大小相差很大,则哈希联接操作通常快得多。    哈希联接可以有效处理未排序的大型非索引输入。
如果两个联接输入都很大,而且这两个输入的大小差不多,则预先排序的合并联接提供的性能与哈希联接相近。但是,如果这两个输入的大小相差很大,则哈希联接操作通常快得多。

   哈希联接可以有效处理未排序的大型非索引输入。它们对复杂查询的中间结果很有用,因为:

           ·    中间结果未经索引(除非已经显式保存到磁盘上然后创建索引),而且通常不为查询计划中的下一个操作进行适当的排序。

          ·     查询优化器只估计中间结果的大小。由于对于复杂查询,估计可能有很大的误差,因此如果中间结果比预期的大得多,则处理中间结果的算法不仅必须有效而且必须适度弱化。

 

  原理

     Hash join一般用于一张小表和一张大表进行join时。Hash join的过程大致如下(下面所说的内存就指sort area,关于过程,后
面会作详细讨论):
    1.  一张小表被hash在内存中。因为数据量小,所以这张小表的大多数数据已经驻入在内存中,剩下的少量数据被放置在临时表空间中;
    2.  每读取大表的一条记录,就和小表中内存中的数据进行比较,如果符合,则立即输出数据(也就是说没有读取临时表空间中的小表的数
据)。而如果大表的数据与小表中临时表空间的数据相符合,则不直接输出,而是也被存储临时表空间中。
    3.  当大表的所有数据都读取完毕,将临时表空间中的数据以其输出。
 
   如果小表的数据量足够小(小于hash area size),那所有数据就都在内存中了,可以避免对临时表空间的读写。
     如果是并行环境下,前面中的第2步就变成如下了:
      2.每读取一条大表的记录,和内存中小表的数据比较,如果符合先做join,而不直接输出,直到整张大表数据读取完毕。如果内存足够,
Join好的数据就保存在内存中。否则,就保存在临时表空间中。


      1,处理大量、未排序、无索引的数据
      2 ,Hash Join一个较大限制是它只能应用于等值联结(equality join),这主要是由于哈希函数及其桶的确定性及无序性所导致的

 

  我们在这里看看blog中的例子:

    原贴:  http://www.cnblogs.com/perfectdesign/archive/2008/04/24/sql_tuning.html

复制代码
这个是一个sql牛人的 博客,他在上面提出了一个小问题:
USE TempDB
GO
CREATE TABLE b1 (blat1 nCHAR(
5
) NOT NULL)
CREATE TABLE b2 (blat2 VARCHAR(
200
) NOT NULL)
GO
INSERT b1
SELECT LEFT(AddressLine1, 
5
) AS blat1 FROM AdventureWorks.Person.Address
INSERT b2
SELECT AddressLine1 AS blat2
FROM AdventureWorks.Person.Address
GO
然后执行如下的查询语句:
SELECT 
*
 FROM b1  
JOIN b2 ON    b2.blat2 LIKE b1.blat1 
+ '%'
复制代码

 

  上面牛人blog提出的问题,不建立任何对象(索引,索引视图等),优化这个语句。其实这就是考察hash联结的使用。

 分析语句:

  1. 选择算法:

     1,由于hash联结只能用相等联结才能使用,这时两个表b1,b2通过like来联结,结果肯定不会是hash联结

     2,由于这里的联结是inner join 而这时使用merge联结同样需要两个字段关联查询,结果肯定不会是merge联结

     3,由于3个联结2个不满足条件,这时优化器只能采用loop嵌套循环联结

  2,如何执行loop联结

    通过上面的分析,我们已经看到了只能采用loop嵌套循环。b1,b2都没有索引。

    假如b1有1万条,b2有2万条。

    看看执行结果:根据嵌套循环算法,是两个循环。由于都没有索引,系统先表扫描b1表1万,在通过逐条表扫描b2两万条。

    最少IO总数: 1万(b1的行数)*表b2的扫描IO次数+b1表扫描IO次数。

    测试上面IO次数计算例子:

      表 [zping.com]中有1000条记录,id为唯一32id,通过id插入数据到b1,b2中。两个表各写入1000行,返回io数:

复制代码

(
1002  行受影响)
表 
'Worktable'。扫描计数 2,逻辑读取 12068 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0
 次。
表 
'b2'。扫描计数 2,逻辑读取 16 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0
 次。
表 
'b1'。扫描计数 3,逻辑读取 4 次,物理读取 0 次,预读 24 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0
 次。
表 
'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
复制代码

    按照上面的公式:4+1002*8=8020次IO 和这里IO次数比较比较起来,差距较大。

    可以看出,IO数要比上面的公式大。

    如果要优化就不能使用嵌套循环算法 。一些网友也给出了解决办法:最优的方法是:

select *
from (select blat1 s from b1) a 
join (select left(blat2,
5 ) s from b2) b
on a.s
=b.s

 如果换成了 

select *
from (select distinct blat1 s from b1) a 
join (select distinct left(blat2,
5 ) s from b2) b
on a.s
=b.s

对比成本,发现hash联结要比merge联结要快,因为这里有一个distinct显示排序操作,数据库会自动采取合并算法。

   因为有了排序操作,成本就比hash慢。

 

   因此最佳优化的SQL语句:

select *
from (select blat1 s from b1) a 
join (select left(blat2,
5 ) s from b2) b
on a.s
=b.s

 

   如何使用Hash联结。

   今天又看了一下阿里巴巴的dba,在Oracle里的研究hash联结的优化和例子:

      http://www.alidba.net/index.php/archives/83

  他得出的结论:
    1. hash的时候一定要用小记录集做驱动.
    2. 大/小记录集作驱动时, 读取数据文件的cost两者是一样的.但是前者的记录集在大到一定程度的时候, 在构建hash桶会产生很多物理读, 而且这些物理读根本无法消除, 每次执行都会产生.


   我们测试一下,看看不同的驱动表对hash联结的性能影响:

    表workflowinfo1 有50多万条记录,表workflowlog1有70多万数据。

   执行一下语句:  

select *  from dbo.workflowinfo1 a
inner hash join dbo.workflowlog1 b on a.workflowid
=
b.workflowid

select 
*
 from dbo.workflowlog1 a
inner hash join dbo.workflowinfo1 b on a.workflowid
=b.workflowid

 一个是以workflowinfo1为驱动表,一个是以workflowlog1为驱动表。对比成本:

  

    这时发现以小的驱动表(workflowinfo1,50多万)成本较少。而多的驱动表(workflowlog1,70多万)成本较高。

 

   这里我们得出结论:

     1,hash联结适合输入和输出都是大型数据集的情况。

     2,联结列必须相等联结,(不相等可以如上方法换成相等联结)

     3,使用较少的表为驱动表。(在使用hash提示联结尤其注意)

分类:  SqlServer

本文转自快乐就好博客园博客,原文链接:http://www.cnblogs.com/happyday56/archive/2009/09/11/1564491.html,如需转载请自行联系原作者
相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
14天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
52 10
|
1月前
|
SQL 数据库 数据安全/隐私保护
Sql Server数据库Sa密码如何修改
Sql Server数据库Sa密码如何修改
|
2月前
|
存储 缓存 负载均衡
一致性 Hash 算法 Hash 环发生偏移怎么解决
一致性 Hash 算法 Hash 环发生偏移怎么解决
90 1
|
24天前
|
SQL
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
17 0
|
14天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
84 6
|
1天前
|
SQL 数据管理 关系型数据库
如何在 Windows 上安装 SQL Server,保姆级教程来了!
在Windows上安装SQL Server的详细步骤包括:从官方下载安装程序(如Developer版),选择自定义安装,指定安装位置(非C盘),接受许可条款,选中Microsoft更新,忽略警告,取消“适用于SQL Server的Azure”选项,仅勾选必要功能(不包括Analysis Services)并更改实例目录至非C盘,选择默认实例和Windows身份验证模式,添加当前用户,最后点击安装并等待完成。安装成功后关闭窗口。后续文章将介绍SSMS的安装。
4 0
|
2天前
|
SQL 关系型数据库 MySQL
:“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server versi
:“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server versi
10 0
|
9天前
|
SQL 安全 网络安全
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
20 0
|
14天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
18天前
|
SQL 数据安全/隐私保护
SQL Server 2016安装教程
SQL Server 2016安装教程
21 1