一、前言:
数据库版本:11.2.0.3
表A1 NUM_ROWS 107,6016(百万级别),没有索引脚本:create table john.A1 as select * from all_objects;(然后运行以下脚本几次,产生大量的数据 insert into john.a1 select * from john.a1)表B1 NUM_ROWS 100CREATE TABLE B1(ID NUMBER);创建表
两表哈希连接是在实际的工作中比较经常遇到的两个表的连接方式,本文档通过实验测试影响两表哈希连接的因素;
二、原理介绍
哈希连接处理的两个数据集分别称为构造输入和探测输入。构造输入为左节点,探测输入为右节点。构造输入的每行记录都会被用来在内存中(或临时表空间,如果没有足够内存可用的话)构造哈希表。当哈希表已经包含构造输入的所有数据时,就开始处理探测输入了。探测输入的每行记录都会被拿来对哈希表拿来对进行探测以找出符合连接条件的记录;
特征:
每个子节点只会执行一次;
哈希表仅由左节点来构造,因此,一般采用最小的那个节点来构造;
只有在左节点完全处理完毕后,才会返回第一条记录;
不支持交叉连接、条件连接和分区外连接;
三、测试环境说明:
插入数据
begin
for i in 1..100 loop
insert into B1 values(i);
if mod(i,100)=0 then
commit;
end if;
end loop;
end;
/
四、测试方法
本文的测试方法,跟嵌套循环连接的方法一样,通过hint的方法来改变执行计划,并进行比较;
测试场景一:直接对量表进行哈希,并比较构造输入为大表和小表时的执行效率;
B1做探测表
select /*+ leading(B1) use_hash(A1,B1) */ *
from a1,b1
where a1.object_id=b1.id;
A1做探测表
select /*+ leading(A1) use_hash(A1,B1) */ *
from a1,b1
where a1.object_id=b1.id;
解读:小表作为探测表的执行效率明显比大表作为探测表的执行效率高很多。
在语句2中的执行计划可以看出没有足够的内存存放A1表,导致哈希的时候数据已经存放到了临时表空间了(磁盘的速度跟内存的速度差距不是一点两点的)
测试场景二:在连接条件A1的OBJECT_ID增加索引,进行检查执行计划,是否走索引;
select /*+ leading(A1) use_hash(A1,B1) */ *
from a1,b1
where a1.object_id=b1.id;
解读:哈希连接时并不会利用连接条件上面的索引;(嵌套连接会利用)
测试三:增加限制条件,并在限制条件上面增加索引;
A1为哈希表:
select /*+ leading(A1) use_hash(A1,B1) */ *
from a1,b1
where a1.object_id=b1.id
AND A1.OBJECT_ID=100;
B1为哈希表:
select /*+ leading(B1) use_hash(A1,B1) */ *
from a1,b1
where a1.object_id=b1.id
AND A1.OBJECT_ID=100;
解读:当限制条件的选择性很强的时候,而这个限制是对大表进行限制的时候,这个时候大表作为哈希表,整体的性能也不会差;
................................................................................... 本文作者:JOHN ORACLE技术博客:ORACLE 猎人笔记
数据库技术群:367875324 (请备注ORACLE管理 )
...................................................................................