日期:2014-05-16  浏览次数:20419 次

Oracle表连接之嵌套循环

在数据库系统中执行一个查询SQL语句,如果这个查询只操作一张表,那么仅仅涉及到这个表及关联对象的访问。访问方式通常是三种:全表扫描、全索引扫描和索引扫描。
如果这个查询操作两张及以上的表,那么需要操作的表之间的连接关系就变得至关重要。
数据库系统执行该SQL时,永远都是两个结果集关联。
例如,
操作三张表,那么就是其中两张表关联出一个结果集,和第三张表关联。
操作四张表,那么就是其中两张表关联出一个结果集,和第三张表关联出一个结果集,再和第四张表关联出最后的结果集。当然也可能是两两关联出两个结果集,再相互关联得到最后的结果集。
操作5张表,各个表之间的关联方式就更复杂了。

这些描述就是数据库系统用来根据操作表的不同排列和组合而生成不同的执行计划。
Oracle数据库系统会使用一种机制,来决定哪一种组合性能最好。这种机制称为基于成本的优化器(Cost-Based Optimization,简称为CBO)。

因为操作多表时,都会按照两表关联操作,最终得出需要的结果集。

Oracle数据库系统将两表关联方式主要分为三种。

这里介绍一下嵌套循环 (Nested? Loops 简称NL) 的连接方式。

嵌套循环,顾名思义就是将一个表为出发点,将该表全部记录逐条去遍历另外一张表的记录,符合条件的就是写入结果集。

例如:
select a.*, b *
from EMP a, DEPT b
where a.DEPTNO = b.DEPTNO;

如使用emp表为出发点,将emp表的记录都查询出来为m条,再将这m条记录的字段deptno值,逐条和dept表的所有记录的deptno字段值匹配,假如dept表有n条记录。
匹配出来的记录符合条件就写入到结果集中。

那么这样关联操作过程中,操作的记录条数就是:先是emp表的m条,接着是dept表n条,但查了m遍,总的记录数就是m+m*n。

如使用dept表为出发点,去遍历emp表,那么总的记录数就是n+n*m。

出发点不同的连接方法,需要的成本就是不一样的。CBO会去最小的那个。

这里作为出发点的表,官方术语将其称为外部表,也叫驱动表。

使用伪代码来表示一下嵌套循环连接

declare
begin
? for outer_table in (select * from emp) loop
?????
??? for inner_table in (select *
????????????????????????? from dept???????????????????????
???????????????????????? where DEPTNO = outer_table.DEPTNO) loop
????? dbms_output.put_line(inner_table.*, outer_table.*);
??? end loop;
?
? end loop;
end;

基于嵌套连接的特点,我们可以想得到,它在两个关联表的数据量相差比较大时采用,但整体上数据量都不应该太大。该关联方式适用于得到小数据量的查询操作。