执计计划,简单说来,就是Oracle通过解读你的SQL,把你想要的结果数据,展现出来。执行计划中,最需要关注的是Id, Operation, Name, Rows.
执行计划中字段的说明
ID:
序号,但不是执行的先后顺序。执行的先后根据缩进判断。这里需要关注,Id前面是否有“*”号。
Operation:
当前操作的内容。表的访问路径或者连接方式。
Name:
Name是语句中对象的名字,可以是表名,索引名,主键名,外键名,视图名,物化视图名等,或者CBO(查询优化器)自动生成的名字。
Rows:
当前操作的基数(Cardinality),Oracle估计当前操作的返回结果集。但是,这个基数,是CBO根据统计信息以及数学公式计算得出的一种推测结果,是不真实的。在带有A-Time的执行计划中,A-Rows的结果,才是真实的。我们在SQL优化的时候,经常需要手工去计算某个访问路径的真实Rows,然后对比执行计划中的Rows。如果Rows中的与手工计算的相差很大,那么往往执行计划就是错误的。
Cost(CPU):
Oracle 计算的一个数值(开销),用于说明SQL执行的开销。对于需要优化的SQL,执行计划往往是有问题的,或者说是错误的,那么这时候,执行计划中的Cost,已经不具有参考意义。
Time:
Oracle 估计当前操作的时间。
SQL> set autotrace trace
SQL> select * from shengfen where id in (select sf_id from chengshi where cs_name = '武威市');
Execution Plan
----------------------------------------------------------
Plan hash value: 404656781
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 42 | 5 (20)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 42 | 5 (20)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 42 | 5 (20)| 00:00:01 |
| 3 | SORT UNIQUE | | 1 | 15 | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | CHENGSHI | 1 | 15 | 3 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | PK_SF_ID | 1 | | 0 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID| SHENGFEN | 1 | 27 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("CS_NAME"='武威市')
5 - access("ID"="SF_ID")
Note
-----
- this is an adaptive plan
Statistics
----------------------------------------------------------
0 recursive calls ## 0 次递归调用
0 db block gets ## 0 次 db 块获取
0 consistent gets ## 0 块逻辑读取
0 physical reads ## 0 次物理读取
0 redo size ## 0 字节重做日志大小
0 bytes sent via SQL*Net to client ## 通过 SQL*Net 发送到客户端的 0 个字节
0 bytes received via SQL*Net from client ## 通过 SQL*Net 从客户端收到 0 个字节
0 SQL*Net roundtrips to/from client ## 0 SQL*Net 往返客户端
0 sorts (memory) ## 0 次排序(内存)
0 sorts (disk) ## 0 次排序(磁盘)
1 rows processed ## 已处理 1 行
SQL>
谓词信息的说明
Predicate Information (identified by operation id):谓词信息(由操作 id 标识)
Filter:
表示谓词条件的值不会影响数据的访问路劲,只起过滤的作用。其算法与标量子查询一样。
Access:
表示这个谓词条件的值将会影响数据的访问路劲(表或索引)。
统计信息的说明
Statistics:统计数据
recursive calls
表示递归调用的次数。一个SQL 第一次执行就会发生硬解析,在硬解析的
时候,优化器会隐含地调用一些内部SQL,因此当一个SQL 第一次执行,recursive calls 会大
于0;第二次执行的时候不需要递归调用,recursive calls 会等于0。
如果SQL 语句中有自定义函数,recursive calls 永远不会等于0,自定义函数被调用了多少次,recursive calls 就会显示为多少次。
db block gets
表示有多少个块发生变化,一般情况下,只有DML 语句才会导致块发生变化,所以查询语句中db block gets 一般为0。如果有延迟块清除,或者SQL 语句中调用了返回CLOB 的函数,db block gets 也有可能会大于0。
consistent gets
表示逻辑读,单位是块。通常情况下逻辑读越小,性能也就越好。但,逻辑读并不是衡量SQL执行快慢的唯一标准,需要结合I/O 等其他综合因素共同判断。
physical reads
表示从磁盘读取了多少个数据块,如果表已经被缓存在buffer cache 中,没有物理读,physical reads 等于0。
redo size
表示产生了多少字节的重做日志,一般情况下只有DML 语句才会产生redo,查询语句一般情况下不会产生redo,所以这里redo size 为0。如果有延迟块清除,查询语句也会产生redo。
bytes sent via SQL*Net to client
表示从数据库服务器发送了多少字节到客户端。
bytes received via SQL*Net from client
表示从客户端发送了多少字节到服务端。
SQL*Net roundtrips to/from client
表示客户端与数据库服务端交互次数,我们可以通过设置arraysize 减少交互次数。
sorts (memory)
和sorts (disk)
分别表示内存排序和磁盘排序的次数。
rows processed
表示SQL 一共返回多少行数据。SQL 优化,可以根据SQL 返回的行数判断整个SQL 应该是走HASH 连接还是走嵌套循环。如果rows processed 很大,一般走HASH 连接;如果rows processed 很小,一般走嵌套循环。