LoveUnix » ORACLE等数据库 » Oracle中的Hash Join祥解
让LU留住您的每

一天 让LU博客留住您的每一天
2007-5-11 18:06 rwq_
Oracle中的Hash Join祥解

[size=3][color=#000000][b][font=宋体][size=10.5pt]一、[/size][/font][/b][b]  hash join[/b][b][font=宋体][size=10.5pt]概念[/size][/font][/b][b][/b][/color][/size]
[align=left][align=left][color=#000000][size=9pt]hash join(HJ)[/size][font=宋体][size=9pt]是一种用于[/size][/font][size=9pt]equi-join[/size][font=宋体][size=9pt](而[/size][/font][size=9pt]anti-join[/size][font=宋体][size=9pt]就是使用[/size][/font][size=9pt]NOT IN[/size][font=宋体][size=9pt]时的[/size][/font][size=9pt]join[/size][font=宋体][size=9pt])的技术。在[/size][/font][size=9pt]Oracle[/size][font=宋体][size=9pt]中,它是从[/size][/font][size=9pt]7.3[/size][font=宋体][size=9pt]开始引入的,以代替[/size][/font][size=9pt]sort-merge[/size][font=宋体][size=9pt]和[/size][/font][size=9pt]nested-loop join[/size][font=宋体][size=9pt]方式,提高效率。在[/size][/font][size=9pt]CBO[/size][font=宋体][size=9pt]([/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]只有在[/size][/font][size=9pt]CBO[/size][font=宋体][size=9pt]才可能被使用到)模式下,优化器计算代价时,首先会考虑[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]可以通过提示[/size][/font][size=9pt]use_hash[/size][font=宋体][size=9pt]来强制使用[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt],也可以通过修改会话或数据库参数[/size][/font][size=9pt]HASH_JOIN_ENABLED=FALSE [/size][font=宋体][size=9pt](默认为[/size][/font][size=9pt]TRUE[/size][font=宋体][size=9pt])强制不使用[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]Hash join[/size][font=宋体][size=9pt]的主要资源消耗在于[/size][/font][size=9pt]CPU[/size][font=宋体][size=9pt](在内存中创建临时的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]表,并进行[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]计算),而[/size][/font][size=9pt]merge join[/size][font=宋体][size=9pt]的资源消耗主要在于此盘[/size][/font][size=9pt]IO[/size][font=宋体][size=9pt](扫描表或索引)。在并行系统中,[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]对[/size][/font][size=9pt]CPU[/size][font=宋体][size=9pt]的消耗更加明显。所以在[/size][/font][size=9pt]CPU[/size][font=宋体][size=9pt]紧张时,最好限制使用[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]在绝大多数情况下,[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]效率比其他[/size][/font][size=9pt]join[/size][font=宋体][size=9pt]方式效率更高:[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]在[/size][/font][size=9pt]Sort-Merge Join(SMJ)[/size][font=宋体][size=9pt],两张表的数据都需要先做排序,然后做[/size][/font][size=9pt]merge[/size][font=宋体][size=9pt]。因此效率相对最差;[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]Nested-Loop Join(NL)[/size][font=宋体][size=9pt]效率比[/size][/font][size=9pt]SMJ[/size][font=宋体][size=9pt]更高。特别是当驱动表的数据量很大(集的势高)时。这样可以并行扫描内表。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]Hash join[/size][font=宋体][size=9pt]效率最高,因为只要对两张表扫描一次。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=9pt][color=#000000] [/color][/size][/align][/align][align=left][align=left][color=#000000][size=9pt]Hash join[/size][font=宋体][size=9pt]一般用于一张小表和一张大表进行[/size][/font][size=9pt]join[/size][font=宋体][size=9pt]时。[/size][/font][size=9pt]Hash join[/size][font=宋体][size=9pt]的过程大致如下(下面所说的内存就指[/size][/font][size=9pt]sort area[/size][font=宋体][size=9pt],关于过程,后面会作详细讨论):[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]1[/size][font=宋体][size=9pt].[/size][/font]
[font=宋体][size=9pt]一张小表被[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]在内存中。因为数据量小,所以这张小表的大多数数据已经驻入在内存中,剩下的少量数据被放置在临时表空间中;[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]2[/size][font=宋体][size=9pt].[/size][/font]
[font=宋体][size=9pt]每读取大表的一条记录,就和小表中内存中的数据进行比较,如果符合,则立即输出数据(也就是说没有读取临时表空间中的小表的数据)。而如果大表的数据与小表中临时表空间的数据相符合,则不直接输出,而是也被存储临时表空间中。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]3[/size][font=宋体][size=9pt].[/size][/font]
[font=宋体][size=9pt]当大表的所有数据都读取完毕,将临时表空间中的数据以其输出。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=9pt][color=#000000] [/color][/size][/align][/align][align=left][align=left][color=#000000]
[font=宋体][size=9pt]如果小表的数据量足够小(小于[/size][/font][size=9pt]hash area size[/size][font=宋体][size=9pt]),那所有数据就都在内存中了,可以避免对临时表空间的读写。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=9pt][color=#000000] [/color][/size][/align][/align][align=left][align=left][color=#000000]
[font=宋体][size=9pt]如果是并行环境下,前面中的第[/size][/font][size=9pt]2[/size][font=宋体][size=9pt]步就变成如下了:[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]2[/size][font=宋体][size=9pt].[/size][/font]
[font=宋体][size=9pt]每读取一条大表的记录,和内存中小表的数据比较,如果符合先做[/size][/font][size=9pt]join[/size][font=宋体][size=9pt],而不直接输出,直到整张大表数据读取完毕。如果内存足够,[/size][/font][size=9pt]Join[/size][font=宋体][size=9pt]好的数据就保存在内存中。否则,就保存在临时表空间中。[/size][/font][size=9pt][/size][/color][/align][/align][size=3][color=#000000][b][font=宋体][size=10.5pt]二、[/size][/font][/b][b]  Oracle[/b][b][font=宋体][size=10.5pt]中与[/size][/font][/b][b]hash join[/b][b][font=宋体][size=10.5pt]相关的参数[/size][/font][/b][b][/b][/color][/size]
[align=left][align=left][color=#000000][font=宋体][size=9pt]首先,要注意的是,[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]只有在[/size][/font][size=9pt]CBO[/size][font=宋体][size=9pt]方式下才会被激活。在[/size][/font][size=9pt]oracle[/size][font=宋体][size=9pt]中与[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]相关的参数主要有以下几个:[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]1[/b][b][font=宋体][size=10.5pt].[/size][/font][/b][b] HASH_JOIN_ENABLED[/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]这个参数是控制查询计划是否采用[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]的[/size][/font][size=9pt]“[/size][font=宋体][size=9pt]总开关[/size][/font][size=9pt]”[/size][font=宋体][size=9pt]。它可以在会话级和实例级被修改。默认为[/size][/font][size=9pt]TRUE[/size][font=宋体][size=9pt],既可以(不是一定,要看优[/size][/font][font=宋体][size=9pt]化器计算出来的代价)使用。如果设为[/size][/font][size=9pt]FALSE[/size][font=宋体][size=9pt],则禁止使用[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]2[/b][b][font=宋体][size=10.5pt].[/size][/font][/b][b] HASH_AREA_SIZE[/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]这个参数控制每个会话的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]内存空间有多大。它也可以在会话级和实例级被修改。默认(也是推荐)值是[/size][/font][size=9pt]sort area[/size][font=宋体][size=9pt]空间大小的两倍([/size][/font][size=9pt]2*SORT_AREA_SIZE[/size][font=宋体][size=9pt])。要提高[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]的效率,就一定尽量保证[/size][/font][size=9pt]sort area[/size][font=宋体][size=9pt]足够大,能容纳下整个小表的数据。但是因为每个会话都会开辟一个这么大的内存空间作为[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]内存,所以不能过大(一般不建议超过[/size][/font][size=9pt]2M[/size][font=宋体][size=9pt])。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]在[/size][/font][size=9pt]Oracle9i[/size][font=宋体][size=9pt]及以后版本中,[/size][/font][size=9pt]Oracle[/size][font=宋体][size=9pt]不推荐在[/size][/font][size=9pt]dedicated server[/size][font=宋体][size=9pt]中使用这个参数来设置[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]内存,而是推荐通过设置[/size][/font][size=9pt]PGA_AGGRATE_TARGET[/size][font=宋体][size=9pt]参数来自动管理[/size][/font][size=9pt]PGA[/size][font=宋体][size=9pt]内存。保留[/size][/font][size=9pt]HASH_AREA_SIZE[/size][font=宋体][size=9pt]只是为了向后兼容。在[/size][/font][size=9pt]dedicated server[/size][font=宋体][size=9pt]中,[/size][/font][size=9pt]hash area[/size][font=宋体][size=9pt]是从[/size][/font][size=9pt]PGA[/size][font=宋体][size=9pt]中分配的,而在[/size][/font][size=9pt]TS(Multi-Threaded Server)[/size][font=宋体][size=9pt]中,[/size][/font][size=9pt]hash area[/size][font=宋体][size=9pt]是从[/size][/font][size=9pt]UGA[/size][font=宋体][size=9pt]中分配的。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]另外,还要注意的是,每个会话并不一定只打开一个[/size][/font][size=9pt]hash area[/size][font=宋体][size=9pt],因为一个查询中可能不止一个[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt],这是就会相应同时打开多个[/size][/font][size=9pt]hash area[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]3[/b][b][font=宋体][size=10.5pt].[/size][/font][/b][b] HAHS_MULTIBLOCK_IO_COUNT[/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]这个参数决定每次读入[/size][/font][size=9pt]hash area[/size][font=宋体][size=9pt]的数据块数量。因此它会对[/size][/font][size=9pt]IO[/size][font=宋体][size=9pt]性能产生影响。他只能在[/size][/font][size=9pt]init.ora[/size][font=宋体][size=9pt]或[/size][/font][size=9pt]spfile[/size][font=宋体][size=9pt]中修改。在[/size][/font][size=9pt]8.0[/size][font=宋体][size=9pt]及之前版本,它的默认值是[/size][/font][size=9pt]1[/size][font=宋体][size=9pt],在[/size][/font][size=9pt]8i[/size][font=宋体][size=9pt]及以后版本,默认值是[/size][/font][size=9pt]0[/size][font=宋体][size=9pt]。一般设置为[/size][/font][size=9pt]1-(65536/DB_BLOCK_SIZE)[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]在[/size][/font][size=9pt]9i[/size][font=宋体][size=9pt]中,这个参数是一个隐藏参数:[/size][/font][size=9pt]_HASH_MULTIBLOCK_IO_COUNT[/size][font=宋体][size=9pt],可以通过表[/size][/font][size=9pt]x$ksppi[/size][font=宋体][size=9pt]查询和修改。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]另外,在[/size][/font][size=9pt]MTS[/size][font=宋体][size=9pt]中,这个参数将不起作用(只会使用[/size][/font][size=9pt]1[/size][font=宋体][size=9pt])。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]它的最大值受到[/size][/font][size=9pt]OS[/size][font=宋体][size=9pt]的[/size][/font][size=9pt]IO[/size][font=宋体][size=9pt]带宽和[/size][/font][size=9pt]DB_BLOCK_SIZE[/size][font=宋体][size=9pt]的影响。既不能大于[/size][/font][size=9pt]MAX_IO_SIZE/DB_BLOCK_SIZE[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]在[/size][/font][size=9pt]8i[/size][font=宋体][size=9pt]及以后版本,如果这个值设置为[/size][/font][size=9pt]0[/size][font=宋体][size=9pt],则表示在每次查询时,[/size][/font][size=9pt]Oracle[/size][font=宋体][size=9pt]自己自动计算这个值。这个值对[/size][/font][size=9pt]IO[/size][font=宋体][size=9pt]性能影响非常大,因此,建议不要修改这个参数,使用默认值[/size][/font][size=9pt]0[/size][font=宋体][size=9pt],让[/size][/font][size=9pt]Oracle[/size][font=宋体][size=9pt]自己去计算这个值。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]如果一定要设置这个值,要保证以下不等式能成立:[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=9pt][color=#000000]R/M < Po2(M/C)[/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]其中,[/size][/font][size=9pt]R[/size][font=宋体][size=9pt]表示小表的大小;[/size][/font][size=9pt]M=HASH_AREA_SIZE*0.9[/size][font=宋体][size=9pt];[/size][/font][size=9pt]Po2(n)[/size][font=宋体][size=9pt]为[/size][/font][size=9pt]n[/size][font=宋体][size=9pt]的[/size][/font][size=9pt]2[/size][font=宋体][size=9pt]次方;[/size][/font][size=9pt]C=HASH_MULTIBLOCK_IO_COUNT*DB_BLOCK_SIZE[/size][font=宋体][size=9pt]。[/size][/font][size=9pt][/size][/color][/align][/align][size=3][color=#000000][b][font=宋体][size=10.5pt]三、[/size][/font][/b][b]  Hash join[/b][b][font=宋体][size=10.5pt]的过程[/size][/font][/b][b][/b][/color][/size]
[align=left][align=left][color=#000000]
[font=宋体][size=9pt]一次完整的[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]如下:[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]1[/b][b][font=宋体][size=10.5pt].计算小表的分区([/size][/font][/b][b]bucket[/b][b][font=宋体][size=10.5pt])数[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][size=3]     [/size][font=宋体][size=9pt]决定[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]的一个重要因素是小表的分区([/size][/font][size=9pt]bucket[/size][font=宋体][size=9pt])数。这个数字由[/size][/font][size=9pt]hash_area_size[/size][font=宋体][size=9pt]、[/size][/font][size=9pt]hash_multiblock_io_count[/size][font=宋体][size=9pt]和[/size][/font][size=9pt]db_block_size[/size][font=宋体][size=9pt]参数共同决定。[/size][/font][size=9pt]Oracle[/size][font=宋体][size=9pt]会保留[/size][/font][size=9pt]hash area[/size][font=宋体][size=9pt]的[/size][/font][size=9pt]20%[/size][font=宋体][size=9pt]来存储分区的头信息、[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]位图信息和[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]表。因此,这个数字的计算公式是:[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000]     [/color][/size][size=9pt]Bucket[/size][font=宋体][size=9pt]数[/size][/font][size=9pt]=0.8*hash_area_size/(hash_multiblock_io_count*db_block_size)[/size][/align][/align][align=left][align=left][size=3][color=#000000][b]2[/b][b][font=宋体][size=10.5pt].[/size][/font][/b][b] Hash[/b][b][font=宋体][size=10.5pt]计算[/size][/font][/b][b]    [/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]读取小表数据(简称为[/size][/font][size=9pt]R[/size][font=宋体][size=9pt]),并对每一条数据根据[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]算法进行计算。[/size][/font][size=9pt]Oracle[/size][font=宋体][size=9pt]采用两种[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]算法进行计算,计算出能达到最快速度的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值(第一[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值和第二[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值)。而关于这些分区的全部[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值(第一[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值)就成为[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]表。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]3[/b][b][font=宋体][size=10.5pt].存放数据到[/size][/font][/b][b]hash[/b][b][font=宋体][size=10.5pt]内存中[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]将经过[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]算法计算的数据,根据各个[/size][/font][size=9pt]bucket[/size][font=宋体][size=9pt]的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值(第一[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值)分别放入相应的[/size][/font][size=9pt]bucket[/size][font=宋体][size=9pt]中。第二[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值就存放在各条记录中。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]4[/b][b][font=宋体][size=10.5pt].创建[/size][/font][/b][b]hash[/b][b][font=宋体][size=10.5pt]位图[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]与此同时,也创建了一个关于这两个[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值映射关系的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]位图。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]5[/b][b][font=宋体][size=10.5pt].[/size][/font][/b][b]
[/b][b][font=宋体][size=10.5pt]超出内存大小部分被移到磁盘[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]如果[/size][/font][size=9pt]hash area[/size][font=宋体][size=9pt]被占满,那最大一个分区就会被写到磁盘(临时表空间)上去。任何需要写入到磁盘分区上的记录都会导致磁盘分区被更新。这样的话,就会严重影响性能,因此一定要尽量避免这种情况。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][size=9pt]2-5[/size][font=宋体][size=9pt]一直持续到整个表的数据读取完毕。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]6[/b][b][font=宋体][size=10.5pt].对分区排序[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]为了能充分利用内存,尽量存储更多的分区,[/size][/font][size=9pt]Oracle[/size][font=宋体][size=9pt]会按照各个分区的大小将他们在内存中排序。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]7[/b][b][font=宋体][size=10.5pt].读取大表数据,进行[/size][/font][/b][b]hash[/b][b][font=宋体][size=10.5pt]匹配[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]接下来就开始读取大表(简称[/size][/font][size=9pt]S[/size][font=宋体][size=9pt])中的数据。按顺序每读取一条记录,计算它的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值,并检查是否与内存中的分区的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值一致。如果是,返回[/size][/font][size=9pt]join[/size][font=宋体][size=9pt]数据。如果内存中的分区没有符合的,就将[/size][/font][size=9pt]S[/size][font=宋体][size=9pt]中的数据写入到一个新的分区中,这个分区也采用与计算[/size][/font][size=9pt]R[/size][font=宋体][size=9pt]一样的算法计算出[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值。也就是说这些[/size][/font][size=9pt]S[/size][font=宋体][size=9pt]中的数据产生的新的分区数应该和[/size][/font][size=9pt]R[/size][font=宋体][size=9pt]的分区集的分区数一样。这些新的分区被存储在磁盘(临时表空间)上。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]8[/b][b][font=宋体][size=10.5pt].完全大表全部数据的读取[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]一直按照[/size][/font][size=9pt]7[/size][font=宋体][size=9pt]进行,直到大表中的所有数据的读取完毕。[/size][/font][size=9pt] [/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]9[/b][b][font=宋体][size=10.5pt].处理没有[/size][/font][/b][b]join[/b][b][font=宋体][size=10.5pt]的数据[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]这个时候就产生了一大堆[/size][/font][size=9pt]join[/size][font=宋体][size=9pt]好的数据和从[/size][/font][size=9pt]R[/size][font=宋体][size=9pt]和[/size][/font][size=9pt]S[/size][font=宋体][size=9pt]中计算存储在磁盘上的分区。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]10[/b][b][font=宋体][size=10.5pt].二次[/size][/font][/b][b]hash[/b][b][font=宋体][size=10.5pt]计算[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]从[/size][/font][size=9pt]R[/size][font=宋体][size=9pt]和[/size][/font][size=9pt]S[/size][font=宋体][size=9pt]的分区集中抽取出最小的一个分区,使用第二种[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]函数计算出并在内存中创建[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]表。采用第二种[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]函数的原因是为了使数据分布[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]性更好。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]11[/b][b][font=宋体][size=10.5pt].二次[/size][/font][/b][b]hash[/b][b][font=宋体][size=10.5pt]匹配[/size][/font][/b][b][/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]在从另一个数据源(与[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]在内存的那个分区所属数据源不同的)中读取分区数据,与内存中的新[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]表进行匹配。返回[/size][/font][size=9pt]join[/size][font=宋体][size=9pt]数据。[/size][/font][size=9pt][/size][/color][/align][/align][align=left][align=left][size=3][color=#000000][b]12[/b][b][font=宋体][size=10.5pt].完成全部[/size][/font][/b][b]hash join[/b][/color][/size][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]继续按照[/size][/font][size=9pt]9-11[/size][font=宋体][size=9pt]处理剩余分区,直到全部处理完毕。[/size][/font][size=9pt] [/size][/color][/align][/align][align=left][align=left][color=#000000][font=宋体][size=9pt]整个[/size][/font][size=9pt]hash join[/size][font=宋体][size=9pt]就完成了。[/size][/font][size=3] [/size][/color][/align][/align][size=3][color=#000000][b][font=宋体][size=10.5pt]四、关于唯一健值的[/size][/font][/b][b]hash[/b][b][font=宋体][size=10.5pt]位图[/size][/font][/b][b][/b][/color][/size]
[align=left][align=left][color=#000000][font=宋体][size=9pt]这个位图包含了每个[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]分区是否有有值的信息。它记录了有数据的分区的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]值。这个位图的最大作用就是,如果[/size][/font][size=9pt]S[/size][font=宋体][size=9pt]表中的数据没有与内存中的[/size][/font][size=9pt]hash[/size][font=宋体][size=9pt]表匹配上,先查看这个位图,已决定是否将没有匹配的数据写入磁盘。那些不可能匹配到的数据(即位图上对应的分区没有数据)就不再写入磁盘。[/size][/font][/color][size=9pt][/size][/align][/align][size=3][color=navy][url=http://www.hellodba.com/Doc/Oracle_Hash_Join.htm]http://www.hellodba.com/Doc/Oracle_Hash_Join.htm[/url][/color][/size]
[align=left][color=navy][size=3][/size][/color][/align]
[size=3][color=#000000][/color][/size]

[[i] 本帖最后由 rwq_ 于 2007-5-11 18:21 编辑 [/i]]

2007-5-12 13:17 五“宅”一生
好东西,谢谢楼主.学习!

2007-6-17 09:09 com_dlj
thanks

2007-6-19 17:15 xj4700
受益菲浅,多谢楼主。

2007-8-16 10:27 ouyelyonghu
good
非常受教

2007-10-5 20:42 gengyonghui
挺详细,顶一个

页: [1]
查看完整版本: Oracle中的Hash Join祥解


Powered by Discuz! Archiver 5.5.0  © 2001-2006 Comsenz Inc.