热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ORACLE数据库查看执行计划的方法

转自:http:www.jb51.netarticle30465.htmhttp:database.51cto.comart200911162180.htm

转自:http://www.jb51.net/article/30465.htm  

          http://database.51cto.com/art/200911/162180.htm

          http://www.2cto.com/database/201109/105188.html

          http://blog.sina.com.cn/s/blog_69e7b8d7010185xq.html

          http://www.cnblogs.com/tracy/archive/2011/09/02/2163462.html


基于ORACLE的应用系统很多性能问题,是由应用系统SQL性能低劣引起的,所以,SQL的性能优化很重要,分析与优化SQL的性能我们一般通过查看该SQL的执行计划,本文就如何看懂执行计划,以及如何通过分析执行计划对SQL进行优化做相应说明

一、什么是执行计划(explain plan) 

执行计划:一条查询语句在ORACLE中的执行过程或访问路径的描述。 

二、如何查看执行计划 

1: 在PL/SQL下按F5查看执行计划。第三方工具toad等。 
很多人以为PL/SQL的执行计划只能看到基数、优化器、耗费等基本信息,其实这个可以在PL/SQL工具里面设置的。可以看到很多其它信息,如下所示 

2: 在SQL*PLUS(PL/SQL的命令窗口和SQL窗口均可)下执行下面步骤 
代码如下:
SQL>EXPLAIN PLAN FOR 
SELECT * FROM SCOTT.EMP; --要解析的SQL脚本 
SQL>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); 



3: 在SQL*PLUS下(有些命令在PL/SQL下无效)执行如下命令: 
代码如下:
SQL>SET TIMING ON             --控制显示执行时间统计数据 
SQL>SET AUTOTRACE ON EXPLAIN       --这样设置包含执行计划、脚本数据输出,没有统计信息 
SQL>执行需要查看执行计划的SQL语句 
SQL>SET AUTOTRACE OFF           --不生成AUTOTRACE报告,这是缺省模式 
SQL> SET AUTOTRACE ON           --这样设置包含执行计划、统计信息、以及脚本数据输出 
SQL>执行需要查看执行计划的SQL语句 
SQL>SET AUTOTRACE OFF 
SQL> SET AUTOTRACE TRACEONLY      --这样设置会有执行计划、统计信息,不会有脚本数据输出 
SQL>执行需要查看执行计划的SQL语句 
SQL>SET AUTOTRACE TRACEONLY STAT --这样设置只包含有统计信息 
SQL>执行需要查看执行计划的SQL语句 

SET AUTOT[RACE] {ON | OFF | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
参考文档:SQLPlus User's Guide and Reference Release 11.1

注意:PL/SQL Developer 工具并不完全支持所有的SQL*Plus命令,像SET AUTOTRACE ON 就如此,在PL/SQL Developer工具下执行此命令会报错
SQL> SET AUTOTRACE ON;
Cannot SET AUTOTRACE

未完,待续。。。。

三、看懂执行计划 
1.执行顺序 
执行顺序的原则是:由上至下,从右向左 
由上至下:在执行计划中一般含有多个节点,相同级别(或并列)的节点,靠上的优先执行,靠下的后执行 
从右向左:在某个节点下还存在多个子节点,先从最靠右的子节点开始执行。 

当然,你在PL/SQL工具中也可以通过它提供的功能来查看执行顺序。如下图所示: 

2.执行计划中字段解释

未完,待续。。。


四、表访问方式 

1.Full Table Scan (FTS) 全表扫描 

为实现全表扫描,Oracle读取表中所有的行,并检查每一行是否满足语句的WHERE限制条件。Oracle顺序地读取分配给表的每个数据块,直到读到表的最高水线处(high water mark, HWM,标识表的最后一个数据块)。一个多块读操作可以使一次I/O能读取多块数据块(db_block_multiblock_read_count参数设定),而不是只读取一个数据块,这极大的减少了I/O总次数,提高了系统的吞吐量,所以利用多块读的方法可以十分高效地实现全表扫描,而且只有在全表扫描的情况下才能使用多块读操作。在这种访问模式下,每个数据块只被读一次。由于HWM标识最后一块被读入的数据,而delete操作不影响HWM值,所以一个表的所有数据被delete后,其全表扫描的时间不会有改善,一般我们需要使用truncate命令来使HWM值归为0。幸运的是oracle 10G后,可以人工收缩HWM的值。
由FTS模式读入的数据被放到高速缓存的Least Recently Used (LRU)列表的尾部,这样可以使其快速交换出内存,从而不使内存重要的数据被交换出内存。
使用FTS的前提条件:在较大的表上不建议使用全表扫描,除非取出数据的比较多,超过总量的5% -- 10%,或你想使用并行查询功能时。

使用全表扫描的例子:
~~~~~~~~~~~~~~~~~~~~~~~~
SQL> explain plan for select * from dual;
Query Plan
-----------------------------------------
SELECT STATEMENT [CHOOSE] Cost=
TABLE ACCESS FULL DUAL

2.Index Lookup 索引扫描 

我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),然后根据rowid直接从表中得到具体的数据,这种查找方式称为索引扫描或索引查找(index lookup)。一个rowid唯一的表示一行数据,该行对应的数据块是通过一次i/o得到的,在此情况下该次i/o只会读取一个数据库块。 23
在索引中,除了存储每个索引的值外,索引还存储具有此值的行对应的ROWID值。索引扫描可以由2步组成:(1) 扫描索引得到对应的rowid值。 (2) 通过找到的rowid从表中读出具体的数据。每步都是单独的一次I/O,但是对于索引,由于经常使用,绝大多数都已经CACHE到内存中,所以第1步的I/O经常是逻辑I/O,即数据可以从内存中得到。但是对于第2步来说,如果表比较大,则其数据不可能全在内存中,所以其I/O很有可能是物理I/O,这是一个机械操作,相对逻辑I/O来说,是极其费时间的。所以如果多大表进行索引扫描,取出的数据如果大于总量的5% -- 10%,使用索引扫描会效率下降很多。

如下列所示:
SQL> explain plan for select empno, ename from emp where empno=10;
Query Plan
------------------------------------
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
INDEX UNIQUE SCAN EMP_I1
注意TABLE ACCESS BY ROWID EMP部分,这表明这不是通过FTS存取路径访问数据,而是通过rowid lookup存取路径访问数据的。在此例中,所需要的rowid是由于在索引查找empno列的值得到的,这种方式是INDEX UNIQUE SCAN查找。

There are 5 methods of index lookup: (根据索引的类型与where限制条件的不同

(1)index unique scan --索引唯一扫描 

通过唯一索引查找一个数值经常返回单个ROWID。如果该唯一索引有多个列组成(即组合索引),则至少要有组合索引的引导列参与到该查询中,如创建一个索引:create index idx_test on emp(ename, deptno, loc)。则select ename from emp where ename = ‘JACK’ and deptno = ‘DEV’语句可以使用该索引。如果该语句只返回一行,则存取方法称为索引唯一扫描。而select ename from emp where deptno = ‘DEV’语句则不会使用该索引,因为where子句种没有引导列。如果存在UNIQUE 或PRIMARY KEY 约束(它保证了语句只存取单行)的话,Oracle经常实现唯一性扫描。

使用唯一性约束的例子:

 
  1. SQL> explain plan for  
  2. select empno,ename from emp where empno=10;  
  3. Query Plan  
  4. SELECT STATEMENT [CHOOSE] Cost=1 
  5. TABLE ACCESS BY ROWID EMP [ANALYZED]  
  6. INDEX UNIQUE SCAN EMP_I1 

(2)index range scan --索引局部(范围)扫描 

使用一个索引存取多行数据,同上面一样,如果索引是组合索引,如(1)所示,而且select ename from emp where ename = ‘JACK’ and deptno = ‘DEV’语句返回多行数据,虽然该语句还是使用该组合索引进行查询,可此时的存取方法称为索引范围扫描。在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如>、<、<>、>=、<=、between)

使用索引范围扫描的例子:

 
  1. SQL> explain plan for select empno,ename from emp  
  2. where empno > 7876 order by empno;  
  3. Query Plan  
  4. SELECT STATEMENT [CHOOSE] Cost=1 
  5. TABLE ACCESS BY ROWID EMP [ANALYZED]  
  6. INDEX RANGE SCAN EMP_I1 [ANALYZED] 

在非唯一索引上,谓词col = 5可能返回多行数据,所以在非唯一索引上都使用索引范围扫描。

使用index rang scan的3种情况:
(a) 在唯一索引列上使用了range操作符(> <<> >= <= between)
(b) 在组合索引上,只使用部分列进行查询,导致查询出多行
(c) 对非唯一索引列上进行的任何查询。

(3)index full scan --索引全局扫描 

与全表扫描对应,也有相应的全Oracle索引扫描。在某些情况下,可能进行全Oracle索引扫描而不是范围扫描,需要注意的是全Oracle索引扫描只在CBO模式下才有效。 CBO根据统计数值得知进行全Oracle索引扫描比进行全表扫描更有效时,才进行全Oracle索引扫描,而且此时查询出的数据都必须从索引中可以直接得到。

全Oracle索引扫描的例子:

 
  1. An Index full scan will not perform single block i/o's and so it may prove to be inefficient.  
  2. e.g.  
  3. Index BE_IX is a concatenated index on big_emp (empno, ename)  
  4. SQL> explain plan for select empno, ename from big_emp order by empno,ename;  
  5. Query Plan  
  6. SELECT STATEMENT [CHOOSE] Cost=26 
  7. INDEX FULL SCAN BE_IX [ANALYZED] 

(4)index fast full scan --索引快速全局扫描,不带order by情况下常发生

扫描索引中的所有的数据块,与 index full scan很类似,但是一个显著的区别就是它不对查询出的数据进行排序,即数据不是以排序顺序被返回。在这种存取方法中,可以使用多块读功能,也可以使用并行读入,以便获得最大吞吐量与缩短执行时间。

索引快速扫描的例子:

 
  1. SQL> explain plan for select empno,ename from big_emp;  
  2. Query Plan  
  3. SELECT STATEMENT [CHOOSE] Cost=1 
  4. INDEX FAST FULL SCAN BE_IX [ANALYZED]  
  5. SQL> explain plan for select ename from big_emp;  
  6. Query Plan  
  7. SELECT STATEMENT [CHOOSE] Cost=1 
  8. INDEX FAST FULL SCAN BE_IX [ANALYZED] 

(5)index skip scan --索引跳跃扫描,where条件列是非索引的前提情况下常发生 

oracle 11g:INDEX   索引跳跃式扫描  (index skip scan)

1.索引跳跃式扫描适合于组合索引,比如(gender,age)

2.当根据组合索引的第一个列gender(leading 列)做查询时,通常是可以用的到索引的

3.当你想使用第二个列age作为筛选条件时,oracle可以使用索引跳跃式扫描

4.跳跃式扫描适合于第一个列值重复比较多,第二个列唯一值比较多的情况

 

SQL> create table demo as select * from emp;

Table created.

 

SQL> create index demo_idx on demo(deptno,sal);

Index created.

 

SQL> analyze table demo compute statistics;

Table analyzed.

 

SQL> set autotrace trace exp

SQL> set linesize 120

 

根据第一个列做条件筛选

SQL> select * from demo where deptno=10;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1165830477

 

----------------------------------------------------------------------------------------

| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------

  0 | SELECT STATEMENT            |          |     5 |   160 |     2   (0)| 00:00:01 |

  1 |  TABLE ACCESS BY INDEX ROWID| DEMO     |     5 |   160 |     2   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | DEMO_IDX |     5 |       |     1   (0)| 00:00:01 |

----------------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   2 - access("DEPTNO"=10)

 

 

根据第二个列做条件筛选

SQL> select * from demo where sal<1500;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 4156203389

 

----------------------------------------------------------------------------------------

| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------

  0 | SELECT STATEMENT            |          |     2 |    64 |     2   (0)| 00:00:01 |

  1 |  TABLE ACCESS BY INDEX ROWID| DEMO     |     2 |    64 |       (0)| 00:00:01 |

|*  2 |   INDEX SKIP SCAN           | DEMO_IDX |     2 |       |     1   (0)| 00:00:01 |

----------------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   2 - access("SAL"<1500)

       filter("SAL"<1500)

 

如果oracle没有使用索引跳跃式扫描的话,可以通过提示index_ss来强制使用,语句如下:

select * from e where sal<1500;

3.Rowid 物理ID扫描 

行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置,所以通过ROWID来存取数据可以快速定位到目标数据上,是Oracle存取单行数据的最快方法。
为了通过ROWID存取表,Oracle 首先要获取被选择行的ROWID,或者从语句的WHERE子句中得到,或者通过表的一个或多个索引的索引扫描得到。Oracle然后以得到的ROWID为依据定位每个被选择的行。
这种存取方法不会用到多块读操作,一次I/O只能读取一个数据块。我们会经常在执行计划中看到该存取方法,如通过索引查询数据。

使用ROWID存取的方法:
SQL> explain plan for select * from dept where rowid = 'AAAAyGAADAAAAATAAF';
Query Plan
------------------------------------
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID DEPT [ANALYZED]

4.Index Full Scan && Index Fast Full Scan && Index Range Scan 区别

Index Full Scan reads the whole index, in an ordered manner (i.e. it "walks" the index from the lowest value to the highest value).(Index Fast Full Scan reads the whole index, without bothering about ordering, it just reads all the index leaf blocks using multiblock reads -- similar to a Table Full Scan).Index Range Scan reads (or expects to read) a limited set of entries from the index. It starts from a certain point in the index and ends at a certain point in the index.

Thus, Index Full Scan reads all the letters from A to Z and reads them in order.Index Fast Full Scan reads all the letters from A to Z but doesn't care to read them in order, it just wants all the letters.Index Range Scanmay be reading from the letter C to the letter G only.


推荐阅读
  • Windows7 64位系统安装PLSQL Developer的步骤和注意事项
    本文介绍了在Windows7 64位系统上安装PLSQL Developer的步骤和注意事项。首先下载并安装PLSQL Developer,注意不要安装在默认目录下。然后下载Windows 32位的oracle instant client,并解压到指定路径。最后,按照自己的喜好对解压后的文件进行命名和压缩。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • Oracle10g备份导入的方法及注意事项
    本文介绍了使用Oracle10g进行备份导入的方法及相关注意事项,同时还介绍了2019年独角兽企业重金招聘Python工程师的标准。内容包括导出exp命令、删用户、创建数据库、授权等操作,以及导入imp命令的使用。详细介绍了导入时的参数设置,如full、ignore、buffer、commit、feedback等。转载来源于https://my.oschina.net/u/1767754/blog/377593。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了将mysql从5.6.15升级到5.7.15的详细步骤,包括关闭访问、备份旧库、备份权限、配置文件备份、关闭旧数据库、安装二进制、替换配置文件以及启动新数据库等操作。 ... [详细]
  • MongoDB用户验证auth的权限设置及角色说明
    本文介绍了MongoDB用户验证auth的权限设置,包括readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase、cluster相关的权限以及root权限等角色的说明和使用方法。 ... [详细]
author-avatar
北京盛世诚泰家具有限公司
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有