数据库表的连接方式 - Hash Join ,Merge Join ,Nested Loop 比较

left join 、right join 、inner join 和 full join 的区别

内连接

外连接:

NESTED LOOP

对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择。在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大(大于 1 万不适合),要把返回子集较小表的作为外表(CBO 默认外表是驱动表),而且在内表的连接字段上一定要有索引。当然也可以用 ORDERED 提示来改变 CBO 默认的驱动表,使用 USE_NL(table_name1 table_name2) 可是强制 CBO 执行嵌套循环连接。

HASH JOIN

散列连接是 CBO 做大数据集连接时的常用方式,优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。

这种方式适用于较小的表完全可以放于内存中的情况,这样总成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高 I/O 的性能。 也可以用 USE_HASH(table_name1 table_name2) 提示来强制使用散列连接。如果使用散列连接 HASH_AREA_SIZE 初始化参数必须足够的大,如果是 9i,Oracle 建议使用 SQL 工作区自动管理,设置 WORKAREA_SIZE_POLICY 为 AUTO,然后调整 PGA_AGGREGATE_TARGET 即可。

MERGE JOIN 排序合并连接

通常情况下散列连接的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接。可以使用 USE_MERGE(table_name1 table_name2) 来强制使用排序合并连接

几种方式的操作方式

merge join

merge join 的操作通常分三步:

  1. 对连接的每个表做 table access full;
  2. 对 table access full 的结果进行排序。
  3. 进行 merge join 对排序结果进行合并。

在全表扫描比索引范围扫描再通过 rowid 进行表访问更可取的情况下,merge join 会比 nested loops 性能更佳。当表特别小或特别巨大的时候,实行全表访问可能会比索引范围扫描更有效。mrege join 的性能开销几乎都在前两步。

hash join

对两个表进行全表扫描,然后 oracle 读取涉及连接的其中一个表,并且在内存里创建来自表的连接列的唯一关键字的位图。当读取和处理第二个表的行时,创建值的位图被用做过滤器。如果一个行成功的通过位图过滤,则 hash 算法用于数据查找和后来的连接。(这里涉及数学问题,我也弄的不是很清楚)。

以下条件下 hash join 可能有优势:

Nested Loops

会循环外表(驱动表),逐个比对和内表的连接是否符合条件。在驱动表比较小,内表比较大,而且内外表的连接列有索引的时候比较好。当 SORT_AREA 空间不足的时候,Oracle 也会选择使用 NL。基于 Cost 的 Oracle 优化器 (CBO) 会自动选择较小的表做外表。

连接方式总结:

  1. 嵌套循环 (nest loop):

    对于被连接的数据子集较小的情况,嵌套循环连接是较好的选择。在嵌套循环中,外表驱动内表,外表返回的每一行都要在内表中检索找到它匹配的行,因此整个查询返回的结果集不能太大(大于 10000 不合适),要把返回子集较小的表作为外表(驱动表),而且在内表的连接字段上一定要有索引。

  2. 哈希连接 (hash join):

    哈希连接是大数据集连接时常用的方式,优化器使用两个表中较小的表,利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。

    这种方式适用于较小的表完全可以放入内存的情况,这样成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段。

    哈希连接只能应用于等值连接 (如 WHERE A.COL3 = B.COL4)、非等值连接 (WHERE A.COL3> B.COL4)、外连接 (WHERE A.COL3 = B.COL4(+))。

  3. 排序合并连接(Sort Merge Join )

    通常情况下哈希连接的效果都比排序合并连接要好。然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序归并连接的性能会忧于哈希连接。

-->