Oracle 表连接的三种方式,带你深入了解表连接

写在前面:今天在一个近两千人的群里面看到有个人在说今天面试的题目,他说当面试官问他表连接的三种方式和他们的区别,他没答上来,我不禁问了问自己表连接的三种方式能说个七七八八,他们有什么区别?所以有了此文。

一.表连接的三种方式

1.NL(嵌套循环)

驱动表(Driving Table)

  • 定义:驱动表是查询中首先被扫描的表。在连接操作中,数据库会从驱动表中逐行读取记录,然后根据连接条件去被驱动表中查找匹配的记录。
  • 选择依据:一般来说,查询优化器会优先选择行数较少或过滤条件效果较好的表作为驱动表,这样可以减少连接操作的次数,提高查询效率。
  • 特点
    • 驱动表的每一条记录都会触发一次对被驱动表的扫描。
    • 优先扫描小表或过滤条件有效的表,能有效减少嵌套循环的次数。

被驱动表(Driven Table)

  • 定义:被驱动表是指在连接过程中由驱动表触发查询的表。驱动表的每一条记录都会对被驱动表进行查找,以满足连接条件。
  • 选择依据:被驱动表通常是行数较多的表,或者在连接条件的字段上有索引的表。使用索引可以提升查询速度。
  • 特点
    • 每次驱动表中的记录都会触发一次对被驱动表的条件查询。
    • 被驱动表的大小和索引情况直接影响查询效率。对于较大的被驱动表,如果缺少有效的索引,查询性能可能会下降显著。

驱动表和被驱动表的选择原则

  • 小表驱动大表:通常会选择记录数较少的表作为驱动表,以减少嵌套循环的次数。
  • 过滤条件强的表作为驱动表:如果某表的过滤条件可以显著减少扫描记录的数量,那么数据库通常会优先选择该表为驱动表。
  • 索引因素:如果被驱动表的连接字段上有索引,则在嵌套循环中可以更快速地定位匹配记录,从而提高连接效率。

 示例:假设有两个表:orders(订单表,有上百万条记录)和 customers(客户表,有几千条记录),我们需要查询每个订单对应的客户信息。查询如下:

SELECT o.order_id, o.order_date, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id;

在这种情况下,customers 表可能会被选择为驱动表,因为它记录数较少,每个客户的信息在 orders 表中可能会有多条记录。通过将小表 customers 作为驱动表,可以减少嵌套次数,从而提升连接效率。

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

  • 数据库从两个表的第一个记录开始逐行扫描。
  • 每次从表A和表B取出一条记录,比较连接字段值:
    • 如果记录匹配连接条件(例如连接字段值相等),则将两条记录合并输出。
    • 如果表A的连接字段值小于表B,则移动表A的指针到下一条记录。
    • 如果表B的连接字段值小于表A,则移动表B的指针到下一条记录。
  • 按照这种方式顺序扫描并比较直到任意一个表达到末尾。

Merge Join示例:

SELECT o.order_id, o.order_date, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
ORDER BY o.customer_id, c.customer_id;
  • 步骤1:如果 orderscustomers 表已经按 customer_id 排序或有索引,则可以直接进入下一步;否则,数据库会先对它们进行排序。
  • 步骤2:Merge Join从 orderscustomers 表的第一个记录开始顺序扫描,并逐行比较 customer_id
    • 当找到相同 customer_id 的记录时,将匹配的记录合并输出。
    • 如果 orders 中的 customer_id 小于 customers 中的 customer_id,则移动 orders 的指针到下一条记录。
    • 如果 customers 中的 customer_id 小于 orders 中的 customer_id,则移动 customers 的指针到下一条记录。

 

看上去合并排序连接要比NL连接更耗时,其实不然,对于相当大的表来说,对于NL,驱动表返回多少条记录就等于访问了多少次被驱动表,但对于排序合并连接来说,顺序扫描减少了随机访问的需求,适合大数据集的连接。

那么merge sort join的优点如下:

  • 效率高:对于已排序的表,Merge Join可以避免排序的开销,只需一次扫描。
  • 适用于大表连接:顺序扫描减少了随机访问的需求,适合大数据集的连接。
  • 支持范围连接:与Hash Join不同,Merge Join支持等值和范围连接。

3.Hash Join 

Hash连接与merge join有点类似,都是基于吞吐量的操作,返回大量的数据的时候要明显比NL要高效,但Hash和merge join还是有区别的,Hash连接不算排序,由PGA中的 HASH_AREA_SIZE参数来控制,而排序合并连接则是由PGA中的SORT_AREA_SIZE参数控制 的。HASH连接使用的是HASH算法,比排序合并连接更高效一些。

 

写到现在,三种表连接的大概步骤已经说明白,但他们有什么不同?

 

下面是我总结的三种表连接方式的不同:


从访问次数来看:

  1. 在NL连接中,驱动表返回多少条记录,被驱动表就访问多少次。在Hash连接与合并排序连接中,驱动表和被驱动表都只会访问0次或者1次。

  2. 在NL连接与Hash连接中有驱动表和被驱动表的概念,在合并排序连接中,根本没有驱动与被驱动的概念。


从驱动顺序来看:

 NL连接和hash连接,驱动表和被驱动表的顺序不同,性能差异很大,而合并排序连接中,由于没有驱动表和被驱动表的概念,在性能上不会有差异

 


从连接排序情况来看:

NL连接 普遍没有Used-Memory关键字,而Hash连接和合并排序连接普遍出现Used-Memory关键字,所以NL连接不需要排序,而Hash连接其实也不需要排序,Hash连接的Uesd-Memory主要用来简历Hash表。和合并排序连接需要大量的排序操作,所以合并排序连接有索引会更高效(因为索引是有序的)。

 


从连接限制方面来看:

哈希连接不支持不等值 <> 连接,不支持>和<的连接方式,也不支持LIKE的连接方式。

排序合并连接不支持的连接条件,也不支持LIKE的连接条件,但比起HASH连接,支持>之类的连接条件。

嵌套循环支持所有SQL写法,无限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值