ORACLE-技术文档-oracle 驱动表(包含 hint使用 nested loop has

2019-01-07 12:03

Oracle 驱动表

Oracle驱动表(driving table/outer table)也叫做外部表,也叫外层表,是在多表关联查询中首先遍历的表,驱动表的每一行都要到另一个表中寻找相应的记录,然后计算返回最终数据。

驱动表的概念只在nested loops和hash join时存在。

原则:

1. 2. 3. 4.

驱动表一般是小表,但不绝对,看下边

驱动表一般是通过where条件筛选后剩余行数较少的表。 如果表的一条记录很长,占用几个数据块也适合做驱动表

CBO和RBO中,对于驱动表的选择是不同的,CBO中通过对统计信息的参考进行计算来选择驱动表,而RBO中按照既定原则选择驱动表。

5. RBO中,from后边最右边的表为驱动表(from后边表从右向左遍历,where条件从下

向上遍历)

6. 涉及驱动表的查询,连接条件的索引很重要,驱动表连接字段可以没有索引,但是被驱

动表需要被扫描驱动表经过筛选后剩余条数的遍数,所以被驱动表的连接字段上有一条索引是非常重要的。

分析:

假设a表10行记录,b表1000行记录,两个表都有id列,查询时使用id列进行关联 Select * from a,b where a.id=b.id and a.id=100;

A表作为驱动表比较合适,假设a.id=100只有1行,即使全表扫描a表也就几个块,假设a表占用10个块。

B表的id假如非唯一,如果b表的id列有索引,b表占用100个块,每个块10行记录,id列索引占用10个块,并且id为100有2条记录,在两个块中 那么这条语句的成本(以块计算,下同):

A表(10个块)*b表索引(10个块)+b表id为100的2个块=102个块 如果b表没有索引,成本为:

A表(10个块)*b表(100个块)=1000个块

如果a,b表都没有索引,可以看出不管哪个表作为驱动表,语句的执行成本都是一样的。 如果a,b表id列都有索引,a表id列索引占2个块,成本为:

A表id列索引(2个块)*b表id列索引(10个块)+b表id为100的2个块=22个块

如果B表的记录很长,可以作为驱动表的情况比较复杂,大家可以自己想象适合的场景。

可以看出,在连接中,如果连接列有索引是多么的重要。

实验支撑

SQL> create table a(id,name) as select object_id,object_name from all_objects where rownum< 200;

Table created.

SQL>

SQL> create table b as select * from all_objects ;

Table created.

SQL> select count(*) from a;

COUNT(*) ---------- 199

SQL> select count(*) from b SQL>

COUNT(*) ---------- 89083

SQL>

SQL> exec dbms_stats.gather_table_stats('TEST','A');

PL/SQL procedure successfully completed.

SQL>

SQL> exec dbms_stats.gather_table_stats('TEST','B');

PL/SQL procedure successfully completed.

两个表都没有索引

Select count(*) from a,b where a.id=b.object_id And a.id=53

执行计划:(B表驱动)

SQL> Select count(*) from a,b where a.id=b.object_id 2 And a.id=53 3 /

COUNT(*) ---------- 1

Execution Plan

---------------------------------------------------------- Plan hash value: 319234518

----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 9 | 420 (1)| 00:00:01 |

| 1 | SORT AGGREGATE | | 1 | 9 | | |* 2 | HASH JOIN | | 1 | 9 | 420 (1)| 00:00:01 | |* 3 | TABLE ACCESS FULL| B | 1 | 5 | 417 (1)| 00:00:01 | |* 4 | TABLE ACCESS FULL| A | 1 | 4 | 3 (0)| 00:00:01 | ----------------------------------------------------------------------------

Predicate Information (identified by operation id): ---------------------------------------------------

2 - access(\ 3 - filter(\ 4 - filter(\

Statistics

---------------------------------------------------------- 1 recursive calls 0 db block gets

1506 consistent gets 0 physical reads 0 redo size

542 bytes sent via SQL*Net to client

543 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client

| 0 sorts (memory) 0 sorts (disk) 1 rows processed

SQL>

A表作为驱动表

SQL> Select /*+ ordered use_nl(a) */count(*) from a,b where a.id=b.object_id 2 And a.id=53;

COUNT(*) ---------- 1

1 row selected.

Execution Plan

---------------------------------------------------------- Plan hash value: 1397777030

----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 9 | 420 (1)| 00:00:01 |

| 1 | SORT AGGREGATE | | 1 | 9 | | |* 2 | HASH JOIN | | 1 | 9 | 420 (1)| 00:00:01 | |* 3 | TABLE ACCESS FULL| A | 1 | 4 | 3 (0)| 00:00:01 | |* 4 | TABLE ACCESS FULL| B | 1 | 5 | 417 (1)| 00:00:01 | ----------------------------------------------------------------------------

Predicate Information (identified by operation id): ---------------------------------------------------

2 - access(\ 3 - filter(\

4 - filter(\

Statistics

---------------------------------------------------------- 1 recursive calls 0 db block gets

| 1506 consistent gets 0 physical reads 0 redo size

542 bytes sent via SQL*Net to client

543 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed

SQL>

发现上面两个语句的代价是一样的

/*+ Ordered use_nl(table_name) */ --使用hint强制表作为驱动表,只使用/*+ use_nl(table1,table2)是无法强制驱动表顺序的,另外,这里使用的use_nl,但是走的是hash join,说明在没有索引的情况下,oracle优化器更倾向hash join,因为nested loop并不一定会提前返回数据。

执行计划下,hash loop下第一个表为驱动表。

表B object_id列有索引的情况

SQL> create index id_b_object_id on b(object_id);

Index created.

SQL> exec dbms_stats.gather_table_stats(ownname => 'TEST',TABNAME => 'B',CASCADE => TRUE);

PL/SQL procedure successfully completed.

SQL>

执行计划:

SQL> Select count(*) from a,b where a.id=b.object_id 2 And a.id=53;

COUNT(*) ---------- 1


ORACLE-技术文档-oracle 驱动表(包含 hint使用 nested loop has.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:解决 Windows XP Service Pack 2 中 Windows 防火墙的设置问题

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: