首页 > 技术文章 > Oracle 执行计划说明

polestar 2013-06-24 20:30 原文

  生成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当前使用的技术,需要用户在分析计划时考虑到这些因素。 当出现这个提示,说明当前表使用了动态采样。 我们从而推断这个表可能没有做过分析。

这里会出现两种情况:

  1. 如果表没有做过分析,那么CBO可以通过动态采样的方式来获取分析数据,也可以或者正确的执行计划。
  2. 如果表分析过,但是分析信息过旧,这时CBO就不会在使用动态采样,而是使用这些旧的分析数据,从而可能导致错误的执行计划。

 

 

推荐阅读