Oracle执行计划 讲解(一)


看懂Oracle执行计划是优化的第一步,让我们从下面的例子开始吧。

        下面为补充内容

1、创建测试表

 
  1. SQL> create table t as select 1 id,object_name from dba_objects;  
  2.    
  3. Table created  
  4.    
  5. SQL> update t set id=99 where rownum=1;  
  6.    
  7. 1 row updated  
  8.    
  9. SQL> commit;  
  10.    
  11. Commit complete  
  12.    
  13. SQL> create index t_ind on t(id);  
  14.    
  15. Index created  

        oracle优化器:RBO和CBO两种, 从oracle10g开始优化器已经抛弃了RBO,下面的列子说明CBO大概是怎样的

 
  1. SQL>  select /*+dynamic_sampling(t 0) */* from t where id=1;  
  2.   
  3. 50819 rows selected.  
  4.   
  5.   
  6. Execution Plan  
  7. ----------------------------------------------------------   
  8. Plan hash value: 1376202287  
  9.   
  10. -------------------------------------------------------------------------------------   
  11. | Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |  
  12. -------------------------------------------------------------------------------------   
  13. |   0 | SELECT STATEMENT            |       |   195 | 15405 |    51   (0)| 00:00:01 |  
  14. |   1 |  TABLE ACCESS BY INDEX ROWID| T     |   195 | 15405 |    51   (0)| 00:00:01 |  
  15. |*  2 |   INDEX RANGE SCAN          | T_IND |    78 |       |    50   (0)| 00:00:01 |  
  16. -------------------------------------------------------------------------------------   
  17.   
  18. Predicate Information (identified by operation id):  
  19. ---------------------------------------------------   
  20.   
  21.    2 - access("ID"=1)  

       现象t表还没有被分析,提示/*+dynamic_sampling(t 0) */*的目的是让CBO无法通过动态采样获取表中的实际数据情况,此时CBO只能根据T表中非常有限的信息(比如表中的extents数量,数据块的数量)来猜测表中的数据。从结果中可以看到CBO猜出表中id=1的有195条,这个数值对于表的总数来说,是一个非常小的值,所以CBO选择了索引而不是全表扫描。
      而实际情况如下所示:
  1. SQL> select * from  t where id=1  
  2.   2  ;  
  3.   
  4. 50819 rows selected.  
  5.   
  6.   
  7. Execution Plan  
  8. ----------------------------------------------------------   
  9. Plan hash value: 1601196873  
  10.   
  11. --------------------------------------------------------------------------   
  12. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  13. --------------------------------------------------------------------------   
  14. |   0 | SELECT STATEMENT  |      | 49454 |  3815K|    67   (2)| 00:00:01 |  
  15. |*  1 |  TABLE ACCESS FULL| T    | 49454 |  3815K|    67   (2)| 00:00:01 |  
  16. --------------------------------------------------------------------------   
  17.   
  18. Predicate Information (identified by operation id):  
  19. ---------------------------------------------------   
  20.   
  21.    1 - filter("ID"=1)  
       通过动态取样,CBO估算出行数为49454,非常接近于真实50820数目。选择了全表扫描。
       我们来收集一下统计信息
 
  1. SQL> exec dbms_stats.gather_table_stats(user,'t',cascade => true);  
  2.   
  3. SQL> select * from  t where id=1;  
  4.   
  5. 50819 rows selected.  
  6.   
  7.   
  8. Execution Plan  
  9. ----------------------------------------------------------   
  10. Plan hash value: 1601196873  
  11.   
  12. --------------------------------------------------------------------------   
  13. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  14. --------------------------------------------------------------------------   
  15. |   0 | SELECT STATEMENT  |      | 50815 |  1339K|    67   (2)| 00:00:01 |  
  16. |*  1 |  TABLE ACCESS FULL| T    | 50815 |  1339K|    67   (2)| 00:00:01 |  
  17. --------------------------------------------------------------------------   
  18.   
  19. Predicate Information (identified by operation id):  
  20. ---------------------------------------------------   
  21.   
  22.    1 - filter("ID"=1)  
现在扫描过的行数为50815。

如果我们更新了所有的id为99看看。
 
  1. SQL> update t set id=99;  
  2.    
  3. 50820 rows updated  
  4.   
  5. SQL> select * from  t where id=99;  
  6.   
  7.   
  8. Execution Plan  
  9. ----------------------------------------------------------   
  10. Plan hash value: 1376202287  
  11.   
  12. -------------------------------------------------------------------------------------   
  13. | Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |  
  14. -------------------------------------------------------------------------------------   
  15. |   0 | SELECT STATEMENT            |       |     1 |    27 |     2   (0)| 00:00:01 |  
  16. |   1 |  TABLE ACCESS BY INDEX ROWID| T     |     1 |    27 |     2   (0)| 00:00:01 |  
  17. |*  2 |   INDEX RANGE SCAN          | T_IND |     1 |       |     1   (0)| 00:00:01 |  
  18. -------------------------------------------------------------------------------------   
  19.   
  20. Predicate Information (identified by operation id):  
  21. ---------------------------------------------------   
  22.   
  23.    2 - access("ID"=99)  
        因为没有对表进行分析,所以表中的分析数据还是之前的信息,CBO并不知道。我们可以看出Rows值为1,也就是说CBO人为表T中的ID=99的值只有1条,所有选择仍然是索引。
 
       我们收集一把统计信息。
 
  1. SQL> exec dbms_stats.gather_table_stats(user,'t',cascade => true);  
  2.    
  3. PL/SQL procedure successfully completed  
  4.   
  5. SQL> select * from  t where id=99;  
  6.   
  7. 50820 rows selected.  
  8.   
  9.   
  10. Execution Plan  
  11. ----------------------------------------------------------   
  12. Plan hash value: 1601196873  
  13.   
  14. --------------------------------------------------------------------------   
  15. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  16. --------------------------------------------------------------------------   
  17. |   0 | SELECT STATEMENT  |      | 50815 |  1339K|    67   (2)| 00:00:01 |  
  18. |*  1 |  TABLE ACCESS FULL| T    | 50815 |  1339K|    67   (2)| 00:00:01 |  
  19. --------------------------------------------------------------------------   
  20.   
  21. Predicate Information (identified by operation id):  
  22. ---------------------------------------------------   
  23.   
  24.    1 - filter("ID"=99)  

      上面为补充内容,下面正式开始

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 下一页

相关内容