关系型数据库并不是最早出现的数据库表现形式,之前还存在层次、网状数据库结构。随着关系型数据库的出现,以数据表的方式进行信息留存的方案迅速发展起来。关系型数据库的重要元素包括数据表和表连接,借助各种类型的表连接,可以将平铺直叙的信息加以组装拼接。
1、Merge Sort Join原理机制
Nest Loop Join嵌套循环是一种比较古老的连接匹配方式,特点是通过两层的循环结构,将符合条件的数据行整理出来。嵌套循环的最大缺陷之一,就是伴随着驱动表被驱动表之间的选择,以及大量随机读现象。
Merge Sort Join连接的优势就是可以一定程度上减少随机读的情况。合并排序连接的最大特征是在一次扫描的同时,就判断连接。不会像Nest Loop Join那样频繁的进行数据读取。使用这种方式的前提,就是连接的两个数据集合必须按照连接列的顺序进行排序。具体操作流程如下:
ü对Merge Sort Join连接而言,不存在驱动表和被驱动表的问题。两边的数据集合没有顺序区别,都要进行排序操作;
ü根据Oracle排序规则和方法,按照连接列的顺序对两个数据集合进行排序;
ü依次对两边的数据集合进行扫描,由于已经是排序过得结果,可以直接确定连接条件是否匹配;
ü确定进行连接的两端数据行,再依据筛选列的要求获取数据;
下面是一个进行Merge Sort Join的执行计划:
//使用Merge Sort Join方法
sql>select /*+use_merge(segs,tabs)*/* from segs,tabs where segs.segment_name=tabs.table_name;
已选择865行。
执行计划
----------------------------------------------------------
Plan hash value: 3475644097
------------------------------------------------------------------------------------
| Id| Operation| Name | Rows| Bytes |TempSpc| Cost (%cpu)| Time|
|0 | SELECT STATEMENT||990 |354K||144(2)| 00:00:02 |
|1 |MERGE JOIN||990 |354K||144(2)| 00:00:02 |
|2 |SORT JOIN||968 |229K|712K|65(2)| 00:00:01 |
|3 |TABLE ACCESS FULL| TABS |968 |229K||11(0)| 00:00:01 |
|*4 |SORT JOIN||2267 |274K|824K|79(2)| 00:00:01 |
|5 |TABLE ACCESS FULL| SEGS |2267 |274K||13(0)| 00:00:01 |
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
filter("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
统计信息
2010recursive calls
0db block gets
378consistent gets
0physical reads
0redo size
72346bytes sent via sql*Net to client
1003bytes received via sql*Net from client
59sql*Net roundtrips to/from client
10sorts (memory)
0sorts (disk)
865rows processed
//使用嵌套循环;
sql>select /*+use_nl(segs,102);background:#C0C0C0;">Plan hash value: 840690564
---------------------------------------------------------------------------
| Id| Operation| Name | Rows| Bytes | Cost (%cpu)| Time|
|0 | SELECT STATEMENT||990 |354K| 11075(1)| 00:02:13 |
|1 |NESTED LOOPS||990 |354K| 11075(1)| 00:02:13 |
|2 |TABLE ACCESS FULL| TABS |968 |229K|11(0)| 00:00:01 |
|*3 |TABLE ACCESS FULL| SEGS |1 |124 |11(0)| 00:00:01 |
3 - filter("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
1930recursive calls
43978consistent gets
70556bytes sent via sql*Net to client
6sorts (memory)
上面代码示例中给出了两个执行计划,给我们如下的信息。
首先,我们观察使用use_merge提示的sql,在Hint的作用下,CBO生成的执行计划中使用Merge Sort Join连接方式。在执行计划中Oracle对两个数据表进行Sort操作,之后对排序过的结果进行Merge连接。其中Oracle对两个数据表进行的都是全表扫描操作。
另一个执行计划是使用use_nl控制的Nest Loop Join连接方式。中间同样也是没有使用索引等方式。其中,产生了大量逻辑读。见下表对比:
对比项目 |
Merge Sort Join |
Nest Loop Join |
逻辑读consistent gets |
378 |
43978 |
排序空间sort |
10 |
6 |