【Oracle优化笔记】哈希连接(HASH JOIN)详解

哈希连接(HASH JOIN)详细执行步骤如下所示:

1.Oracle根据HASH_AREA_SIZEDB_BLOCK_SIZE_HASH_MUTBLOCK_IO_COUNT的值来决定HASH Partition的数量(HASH PARTITION是将结果集分为若干个分区,每个分区有相同数量的bucketbuckethash映射的单位,而partition则是I/O单位)。Oracle会保留hash area20%来存储分区的头信息、hash位图信息和hash表。因此,这个数字的计算公式是:
     Partition=0.8*hash_area_size/(hash_multiblock_io_count*db_block_size)

各参数含义后边解释。

2.在表1和表2施加指定的谓词条件之后,结果集较小的那个作为驱动结果集,记为S,结果集较大的那个是被驱动结果集,记为B

3.oracle遍历S,一条条读取记录,并对连接列的值通过两个哈希算法进行哈希运算,得到两个值hash1hash2。然后根据hash1的值将S中对应的记录放到对应的hash partitionhash bucket之中,同时存储进去的还有hash2的值。如果在读取过程中hash area已经满了,那么oracle会选择记录量最大的hash partition写入到磁盘中(临时表空间),如果之后再有需要放到该partition的值,那么就会更新磁盘,如果频繁更新磁盘会导致性能问题。在构建hash partition时会同时构建一个BITMAP,记录该partition当中每个bucket是否为空。遍历完后oracle会根据每个partition当中的记录数做一个排序,将记录数少的partition优先放到内存中,以保证尽量多的partition保留在内存中。

4.之后开始遍历B,也针对每一条记录使用两个哈希算法计算出两个值hash1hash2。根据计算出来的hash1去寻找匹配的hash partition以及hash bucket,然后对hash bucket当中的每条记录进行匹配,校验连接列数据是否真的相等。如果BITMAP显示对应的hash bucket中有数据却在内存中找不到,说明该hash bucket已经刷新到磁盘当中。这时候会再建立一个hash partition记录这个数据,刷新到磁盘中,如果没有对应的hash bucket则说明B中的该记录在S中不存在匹配的数据,则不需要再进行保留。

5.之上的顺序做完之后能保证在内存中的数据已经进行了匹配,剩下的就是SB存储在磁盘上的记录。此时因为已经通过计算完的hash1进行了partitionbucket的分配,剩下的就是对相对应的partition和 Bpartition进行匹配,这个匹配过程中会使用hash2的值再构建hash table,用于分开数据记录,以方便进行匹配。

6.最后所有匹配成功的记录就是哈希连接后所对应的结果集。

 

 

下面是一开始的几个参数的介绍:

1.HASH_AREA_SIZE
     这个参数控制每个会话的hash内存空间有多大。它也可以在会话级和实例级被修改。默认(也是推荐)值是sort area空间大小的两倍
2*SORT_AREA_SIZE)。要提高hash join的效率,就一定尽量保证sort area足够大,能容纳下整个小表的数据。但是因为每个会话都会
开辟一个这么大的内存空间作为hash内存,所以不能过大(一般不建议超过2M)。
     在Oracle9i及以后版本中,Oracle不推荐在dedicated server中使用这个参数来设置hash内存,而是推荐通过设置
PGA_AGGRATE_TARGET参数来自动管理PGA内存。保留HASH_AREA_SIZE只是为了向后兼容。在dedicated server中,hash area是从
PGA中分配的,而在MTS(Multi-Threaded Server)中,hash area是从UGA中分配的。
     另外,还要注意的是,每个会话并不一定只打开一个hash area,因为一个查询中可能不止一个hash join,这是就会相应同时打开多个
hash area
2.HAHS_MULTIBLOCK_IO_COUNT
     这个参数决定每次读入hash area的数据块数量。因此它会对IO性能产生影响。他只能在init.oraspfile中修改。在8.0及之前版本,
它的默认值是1,在8i及以后版本,默认值是0。一般设置为1-(65536/DB_BLOCK_SIZE)
     在9i中,这个参数是一个隐藏参数:_HASH_MULTIBLOCK_IO_COUNT,可以通过表x$ksppi查询和修改。
     另外,在MTS中,这个参数将不起作用(只会使用1)。
     它的最大值受到OSIO带宽和DB_BLOCK_SIZE的影响。既不能大于MAX_IO_SIZE/DB_BLOCK_SIZE
     在8i及以后版本,如果这个值设置为0,则表示在每次查询时,Oracle自己自动计算这个值。这个值对IO性能影响非常大,因此,建议不要
修改这个参数,使用默认值0,让Oracle自己去计算这个值。
     如果一定要设置这个值,要保证以下不等式能成立:
     R/M < Po2(M/C)
     其中,R表示小表的大小;M=HASH_AREA_SIZE*0.9Po2(n)n2次方;C=HASH_MULTIBLOCK_IO_COUNT*DB_BLOCK_SIZE

 

 

最后附上从网上看到的一个对hash join的优化案例,感觉很不错:

http://www.itpub.net/forum.php?mod=viewthread&tid=1191228

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值