首先创建测试的表:
SQL> show user USER 为 "U1" SQL> create table t1 (id int,name varchar2(1000)); 表已创建。 SQL> create table t2 (id int,name varchar2(1000)); 表已创建。 SQL> create index ind_t1 on t1(id); 索引已创建。 SQL> create index ind_t2 on t2(id); 索引已创建。 SQL> create index ind_t2_name on t2(name); 索引已创建。 SQL> conn /as sysdba 已连接。 SQL> insert into u1.t1 select object_id,object_name from dba_objects; 已创建50607行。 SQL> commit; 提交完成。
SQL> set autotrace traceonly SQL> select t1.* from t1,t2 where t1.id = t2.id and t1.id = 5 and t2.name = 'A'; 未选定行 执行计划 ---------------------------------------------------------- Plan hash value: 1946640164 ---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 1030 | 4 (0)| 00:00:01 | | 1 | MERGE JOIN CARTESIAN | | 1 | 1030 | 4 (0)| 00:00:01 | |* 2 | TABLE ACCESS FULL | T2 | 1 | 515 | 2 (0)| 00:00:01 | | 3 | BUFFER SORT | | 1 | 515 | 2 (0)| 00:00:01 | | 4 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 515 | 2 (0)| 00:00:01 | |* 5 | INDEX RANGE SCAN | IND_T1 | 1 | | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("T2"."NAME"='A' AND "T2"."ID"=5) 5 - access("T1"."ID"=5) Note ----- - dynamic sampling used for this statement 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 3 consistent gets 0 physical reads 0 redo size 326 bytes sent via SQL*Net to client 389 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 0 rows processed
|* 5 | INDEX RANGE SCAN | IND_T1 | 1 | | 1 (0)| 00:00:01 |
当两行的缩进一样时,最上面的最先被执行,在这里就是ID=2:
|* 2 | TABLE ACCESS FULL | T2 | 1 | 515 | 2 (0)| 00:00:01 |然后是ID=3:
| 3 | BUFFER SORT | | 1 | 515 | 2 (0)| 00:00:01 |根据上面的规则,整个的执行顺序就是:5 --> 4 --> 2 --> 3 --> 1 --> 0。这就是整个sql的执行过程。
Id:是一个序号,注意,他的大小并不是执行的先后顺序。
Operation:是当前操作的内容。
Name:当前操作的对象。
Rows:就是当前操作的cardinality,oracle估算当前操作的返回结果集。
Cost:oracle计算出来的一个数值(代价),用于说明sql执行的代价。
Time :oracle估算当前操作的时间。
执行计划中还有一些比较有用的信息:
Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("T2"."NAME"='A' AND "T2"."ID"=5) 5 - access("T1"."ID"=5)
这一段用来说明谓词信息和数据获取的方式。意思就是在第一步使用了如下过滤条件:
5 - access("T1"."ID"=5)第三步使用了如下过滤条件:
2 - filter("T2"."NAME"='A' AND "T2"."ID"=5)这里要注意access和filter的区别:
access:表示这个谓词条件的值将会影响数据的访问路劲(表还是索引,在这里索引 IND_T1)。
filter:表示谓词条件的值并不会影响数据访问的路径,只起到过滤的作用。
在我们看执行计划的时候,如果谓词是access的,就要思考对于谓词的条件,使用的访问路径是否正确。执行计划下面是:
Note ----- - dynamic sampling used for this statement这一步提示当前表使用了动态采样,通过这个提示,我们就知道,这个表可能没有做过分析。我们把整个sql的执行过程翻译成语言描述大概如下:
这个执行计划采用了动态采样收集统计信息。
ID=5:首先根据索引 IND_T1 找到符合过滤条件("T1"."ID"=5)的记录,这里oracle估算到大概有1行记录。
ID=4:然后oracle根据rowid找到t1表中的这条记录。
ID=2:然后全表扫描t2,使用的过滤条件是("T2"."NAME"='A' AND "T2"."ID"=5)。
ID=3:然后在内存中排序。
ID=1:然后t1表和t2表做关联。
ID=0:然后将结果返回。
在最后面还有使用oracle资源的统计信息:
统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 3 consistent gets 0 physical reads 0 redo size 326 bytes sent via SQL*Net to client 389 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 0 rows processed0 recursive calls:在执行这个sql语句中oracle内部额外执行的sql语句的个数。