1. 什么是 Hash Join
当sqlserver需要对包含大量记录的表做join的时候,往往会选择hash join,因为hash join性能优异。另外,hash join支持各种外连接和半连接。
Hash Join包含两个阶段。
第一阶段是build,sqlserver会读取一个表的所有记录生成一个保存在内存中的hash表。这个阶段往往会选择较小的表生成hash表,因为hash表太大的话会占大量内存,而且也会消耗较多的cpu资源。build阶段选择的表也称为left input或者build input。另外,hash表的key就是两个表join的equijoin字段。
第二阶段是probe,sqlserver会逐一迭代另一个表的所有记录来查询hash表,从而生成join结果。probe阶段选择的表也称为right input或者probe input。
以下的伪码说明了hash join的算法。
for each row R1 in the build table
begin
calculate hash value on R1 join key(s)
insert R1 into the hash table
end
for each row R2 in the probe table
begin
calculate hash value on R2 join key(s)
query the hash table, if R1 joins with R2
output (R1, R2)
end
从以上算法我们可以知道,在build阶段,hash join不会输出任何结果;从probe阶段开始,hash join才会输出结果。
2. hash join的内存分配
如前文所说,build阶段的hash表非常消耗内存。所以sqlserver会从做join操作的两个表中选择较小的那个表来生成hash表,并且根据这个表的大小来预估并分配所需的内存。但是,如果内存不够会怎样?这种情况下,hash表会有一小部分保存在磁盘上,其他部分仍然保存在内存中。当我们从build input中读取一条新的记录的时候,如果hash表在内存中,那么我们就把记录写进内存;如果hash表在磁盘上,那么我们就把记录写进磁盘。类似地,probe阶段如果内存不够,也会把部分记录写进磁盘。
3. hash join tree的类型<