生成SQL的执行计划是Oracle在对SQL做硬解析时的一个非常重要的步骤,它制定出一个方案告诉Oracle在执行这条SQL时以什么样的方式访问数据:索引还是全表扫描,是Hash Join还是Nested loops Join等。先看一个例子:
-bash-3.00$ sqlplus hr/hr123 #以hr用户登录数据库 SQL> set autotrace traceonly; --开启autotrace功能 SQL> select 2 t1.first_name,last_name 3 from employees t1, jobs t2 4 where t1.job_id=t2.job_id; 107 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1445457117 ------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 107 | 2568 | 3 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| EMPLOYEES | 107 | 2568 | 3 (0)| 00:00:01 | ------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 8 recursive calls 0 db block gets 17 consistent gets 0 physical reads 0 redo size 3058 bytes sent via SQL*Net to client 462 bytes received via SQL*Net from client 9 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 107 rows processed SQL>
执行计划中字段解释:
1 ID: 一个序号,但不是执行的先后顺序。执行的先后根据缩进来判断。 2 Operation: 当前操作的内容。 3 Rows: 当前操作的Cardinality,Oracle估计当前操作的返回结果集。 4 Cost(CPU):Oracle 计算出来的一个数值(代价),用于说明SQL执行的代价。 5 Time:Oracle 估计当前操作的时间。
Cardinality值表示CBO预期从一个行源(row source)返回的记录数,这个行源可能是一个表,一个索引,也可能是一个子查询。 在Oracle 9i中的执行计划中,Cardinality缩写成Card。 在10g中,Card值被rows替换。
Cardinality的值对于CBO做出正确的执行计划来说至关重要。 如果CBO获得的Cardinality值不够准确(通常是没有做分析或者分析数据过旧造成),在执行计划成本计算上就会出现偏差,从而导致CBO错误的制定出执行计划。
在多表关联查询或者SQL中有子查询时,每个关联表或子查询的Cardinality的值对主查询的影响都非常大,甚至可以说,CBO就是依赖于各个关联表或者子查询Cardinality值计算出最后的执行计划。
统计信息说明:
1 db block gets : 从buffer cache中读取的block的数量 2 consistent gets: 从buffer cache中读取的undo数据的block的数量 3 physical reads: 从磁盘读取的block的数量 4 redo size: DML生成的redo的大小 5 sorts (memory) :在内存执行的排序量 6 sorts (disk) :在磁盘上执行的排序量
Physical Reads通常是我们最关心的,如果这个值很高,说明要从磁盘请求大量的数据到Buffer Cache里,通常意味着系统里存在大量全表扫描的SQL语句,这会影响到数据库的性能,因此尽量避免语句做全表扫描,对于全表扫描的SQL语句,建议增 加相关的索引,优化SQL语句来解决。
用以下语句可以查看数据缓冲区的命中率:
1 SQL> SELECT name, value FROM v$sysstat WHERE name IN ('db block gets', 'consistent gets','physical reads'); 2 3 NAME VALUE 4 ---------------------------------------------------------------- ---------- 5 db block gets 439264 6 consistent gets 195214 7 physical reads 10667 8 9 SQL> 10 11 --数据缓冲区的使用命中率=1 - ( physical reads / (db block gets + consistent gets) )。 12 13 SQL> select 1-(10667/(439264+195214)) from dual; 14 15 1-(10667/(439264+195214)) 16 ------------------------- 17 .983187754 18 19 SQL>
查询出来的结果Buffer Cache的命中率应该在90%以上,否则需要增加数据缓冲区的大小。
动态分析:
如果在执行计划中有如下提示:
Note ------------ -dynamic sampling used for the statement
这提示用户CBO当前使用的技术,需要用户在分析计划时考虑到这些因素。 当出现这个提示,说明当前表使用了动态采样。 我们从而推断这个表可能没有做过分析。
这里会出现两种情况: