如何查看oracle执行计划

1      查看Oracle执行计划的几种方法

1.1      通过PL/SQL Dev工具

1、直接File->New->Explain Plan Window,在窗口中执行sql可以查看计划结果。其中,Cost表示cpu的消耗,单位为n%Cardinality表示执行的行数,等价Rows

 2、先执行 explain plan for  select * from dual,再 select * from table(dbms_xplan.display)便可以看到oracle的执行计划了,看到的结果和1中的一样,所以使用工具的时候推荐使用1方法。

注意:PL/SQL Dev工具的Command window中不支持set autotrance on的命令。还有使用工具方法查看计划看到的信息不全,有些时候我们需要sqlplus的支持。

1.2      通过sqlplus

1.最简单的办法

Sql> set autotrace on

Sql> select * from dual;

  执行完语句后,会显示explain plan 与统计信息。

  这个语句的优点就是它的缺点,这样在用该方法查看执行时间较长的sql语句时,需要等待该语句执行成功后,才返回执行计划,使优化的周期大大增长。如果不想执行语句而只是想得到执行计划可以采用:

Sql> set autotrace traceonly

这样,就只会列出执行计划,而不会真正的执行语句,大大减少了优化时间。虽然也列出了统计信息,但是因为没有执行语句,所以该统计信息没有用处,如果执行该语句时遇到错误,解决方法为:

(1)在要分析的用户下:

Sqlplus > @?\rdbms\admin\utlxplan.sq

(2) sys用户登陆

Sqlplus > @ ?sqlplus\admin\plustrce.sql

Sqlplus > grant plustrace to user_name;

- - user_name是上面所说的分析用户

 

2.用explain plan命令

(1) sqlplus > explain plan for select * from dual;

(2) sqlplus > select * from table(dbms_xplan.display);

上面这2种方法只能为在本会话中正在运行的语句产生执行计划,即我们需要已经知道了哪条语句运行的效率很差,我们是有目的只对这条SQL语句去优化。其实,在很多情况下,我们只会听一个客户抱怨说现在系统运行很慢,而我们不知道是哪个SQL引起的。此时有许多现成的语句可以找出耗费资源比较多的语句,如:

SELECT ADDRESS, substr(SQL_TEXT,1,20) Text, buffer_gets, executions,

buffer_gets/executions AVG  FROM  v$sqlarea

WHERE executions>0 AND buffer_gets > 100000   ORDER BY 5;

ADDRESS      TEXT                     BUFFER_GETS    EXECUTIONS        AVG

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

66D83D64   select t.name,  (sel               421531        60104             7.01336017

66D9E8AC   select t.schema, t.n               1141739        2732             417.913250

66B82BCC   select s.synonym_nam             441261        6                73543.5

  从而对找出的语句进行进一步优化。当然我们还可以为一个正在运行的会话中运行的所有SQL语句生成执行计划,这需要对该会话进行跟踪,产生trace文件,然后对该文件用tkprof程序格式化一下,这种得到执行计划的方式很有用,因为它包含其它额外信息,如SQL语句执行的每个阶段(ParseExecuteFetch)分别耗费的各个资源情况(CPUDISKelapsed)

1.3      启用SQL_TRACE跟踪所有后台进程活动:

全局参数设置: .OracleHome/admin/SID/pfile中指定: SQL_TRACE = true (10g)

    当前session中设置:

    SQL> alter session set SQL_TRACE=true;

    SQL> select * from dual;

    SQL> alter session set SQL_TRACE=false;

    对其他用户进行跟踪设置:

    SQL> select sid,serial#,username from v$session where username='XXX';

       SID    SERIAL# USERNAME

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

       127      31923 A

       128      54521 B

    开启跟踪:SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,true);

    关闭跟踪:SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,false);

    然后使用oracle自带的tkprof命令行工具格式化跟踪文件。

1.4      使用tkprof格式化跟踪文件: 

一般,一次跟踪可以分为以下几步:

1、界定需要跟踪的目标范围,并使用适当的命令启用所需跟踪。

2、经过一段时间后,停止跟踪。此时应该产生了一个跟踪结果文件。

3、找到跟踪文件,并对其进行格式化,然后阅读或分析。

--使用一下SQL找到当前session的跟踪文件:

SELECT d.value|| '/' ||lower(rtrim(i.instance, chr( 0 )))|| '_ora_' ||p.spid|| '.trc'trace_file_name
from
select p.spid from v$mystat m,v$session s, v$process p
where m.statistic# = 1 and s.sid = m.sid and p.addr = s.paddr) p,
select t.instance from v$thread t,v$parameter v
where v.name = 'thread' and (v.value = 0 or t.thread# = to_number(v.value))) i,
select value from v$parameter where name = 'user_dump_dest' ) d;
-- 其它用户的 session
    SELECT d.value|| '/' ||lower(rtrim(i.instance, chr( 0 )))|| '_ora_' ||p.spid|| '.trc'trace_file_name
    from
    ( select p.spid from v$session s, v$process p
          where s.sid= '27' and s. SERIAL#= '30' and p.addr = s.paddr) p,
    ( select t.instance from v$thread t,v$parameter v
          where v.name = 'thread' and (v.value = 0 or t.thread# = to_number(v.value))) i,
    ( select value from v$parameter where name = 'user_dump_dest' ) d; 

--查找后使用tkprof命令,TRACE文件格式为到D盘的explain_format.txt文件中

SQL> $tkprof d:/oracle/admin/FZLGFM/udump/fzlgfm_ora_3468.trc  d:/explain_format.txt

文件内容大致如下

TKPROF: Release 9.2.0.1.0 - Production on 星期二 4 20 13:59:20 2010

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

Trace file: d:/oracle/admin/FZLGFM/udump/fzlgfm_ora_3468.trc

Sort options: default

********************************************************************************

count    = number of times OCI procedure was executed

cpu      = cpu time in seconds executing

elapsed  = elapsed time in seconds executing

disk     = number of physical reads of buffers from disk

query    = number of buffers gotten for consistent read

current  = number of buffers gotten in current mode (usually for update)

rows     = number of rows processed by the fetch or execute call
********************************************************************************

alter session set events '10046 trace name context forever, level 8' 

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        0      0.00       0.00          0          0          0           0

Execute      1      0.00       0.00          0          0          0           0

Fetch        0      0.00       0.00          0          0          0           0

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

total        1      0.00       0.00          0          0          0           0 

Misses in library cache during parse: 0

Misses in library cache during execute: 1

Optimizer goal: CHOOSE

Parsing user id: SYS

2      如何看懂ORACLE执行计划

2.1      什么是执行计划

    An explain plan is a representation of the access path that is taken when a query is executed within Oracle.

2.2      如何访问数据

    At the physical level Oracle reads blocks of data. The smallest amount of data read is a single Oracle block, the largest is constrained by operating system limits (and multiblock i/o). Logically Oracle finds the data to read by using the following methods:
    Full Table Scan (FTS)    --
全表扫描
    Index Lookup (unique & non-unique)    --索引扫描(唯一和非唯一)
    Rowid    --物理行id

2.3      执行计划层次关系

When looking at a plan, the rightmost (ie most inndented) uppermost operation is the first thing that is executed.  --采用最右最上最先执行的原则看层次关系,在同一级如果某个动作没有子ID就最先执行

2.3.1        例子解说

Execution Plan

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

0 **SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=8 Bytes=248)

1 0 **HASH JOIN (Cost=3 Card=8 Bytes=248)

2 1 ****TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=3 Bytes=36)

3 1 ****TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=16 Bytes=304)

左侧的两排数据,前面的是序列号ID,后面的是对应的PID(父ID)。

A shortened summary of this is:

Execution starts with ID=0: SELECT STATEMENT but this is dependand on it's child objects

So it executes its first child step: ID=1 PID=0 HASH JOIN but this is dependand on it's child objects

So it executes its first child step: ID=2 PID=1 TABLE ACCESS (FULL) OF 'DEPT'

Then the second child step: ID=3 PID=2 TABLE ACCESS (FULL) OF 'EMP'

Rows are returned to the parent step(s) until finished

2.4      表访问方式

2.4.1        Full Table Scan (FTS) 全表扫描

In a FTS operation, the whole table is read up to the high water mark (HWM). The HWM marks the last block in the table that has ever had data written to it. If you have deleted all the rows then you will still read up to the HWM. Truncate resets the HWM back to the start of the table. FTS uses multiblock i/o to read the blocks from disk.   --全表扫描模式下会读数据到表的高水位线(HWM即表示表曾经扩展的最后一个数据块),读取速度依赖于Oracle初始化参数db_block_multiblock_read_count(我觉得应该这样翻译:FTS扫描会使表使用上升到高水位(HWM),HWM标识了表最后写入数据的块,如果你用DELETE删除了所有的数据表仍然处于高水位(HWM),只有用TRUNCATE才能使表回归,FTS使用多IO从磁盘读取数据块).

2.4.2        Index Lookup 索引扫描

There are 5 methods of index lookup:

index unique scan   --索引唯一扫描

Method for looking up a single key value via a unique index. always returns a single value, You must supply AT LEAST the leading column of the index to access data via the index.

eg:SQL> explain plan for select empno,ename from emp where empno=10; 

index range scan   --索引局部扫描

Index range scan is a method for accessing a range values of a particular column. AT LEAST the leading column of the index must be supplied to access data via the index. Can be used for range operations (e.g. > < <> >= <= between) .

eg:SQL> explain plan for select mgr from emp where mgr = 5;

 index full scan   --索引全局扫描

Full index scans are only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort. For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order.

eg: SQL> explain plan for select empno,ename from big_emp order by empno,ename;

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

Scans all the block in the index, Rows are not returned in sorted order, Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO, may be hinted using INDEX_FFS hint, uses multiblock i/o, can be executed in parallel, can be used to access second column of concatenated indexes. This is because we are selecting all of the index.

eg: SQL> explain plan for select empno,ename from big_emp;

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

Index skip scan finds rows even if the column is not the leading column of a concatenated index. It skips the first column(s) during the search.

eg:SQL> create index i_emp on emp(empno, ename);

SQL> select /*+ index_ss(emp i_emp)*/ job from emp where ename='SMITH';

2.4.3        .Rowid 物理ID扫描

This is the quickest access method available.Oracle retrieves the specified block and extracts the rows it is interested in.   --Rowid扫描是最快的访问数据方式

 

看执行计划时,我们的关键不是看哪个操作先执行,哪个操作后执行,而是关键看表之间连接的顺序(如得知哪个为驱动表,这需要从操作的顺序进行判断)、使用了何种类型的关联及具体的存取路径(如判断是否利用了索引)

在从执行计划中判断出哪个表为驱动表后,根据我们的知识判断该表作为驱动表是否合适,如果不合适,对SQL语句进行更改,使优化器可以选择正确的驱动表。

3      执行计划稳定性能带给我们什么

Oracle存在着执行计划选择失误的可能。这也是我们经常遇见的一些现象,比如总有人说我的程序在测试数据库中跑的很好,但在产品数据库上就是跑的很差,甚至后者硬件条件比前者还好,这到底是为什么?硬件资源、统计信息、参数设置都可能对执行计划产生影响。由于因素太多,我们总是对未来怀着一种莫名的恐惧,我的产品数据库上线后到底跑的好不好?于是Oracle提供了一种稳定执行计划的能力,也就是把在测试环境中的运行良好的执行计划所产生的OUTLINES移植到产品数据库,使得执行计划不会随着其他因素的变化而变化。

那么OUTLINES是什么呢?先要介绍一个内容,Oracle提供了在SQL中使用HINTS来引导优化器产生我们想要的执行计划的能力。这在多表连接、复杂查询中特别有效。HINTS的类型很多,可以设置优化器目标(RULECHOOSEFIRST_ROWSALL_ROWS),可以指定表连接的顺序,可以指定使用哪个表的哪个索引等等,可以对SQL进行很多精细的控制。通过这种方式产生我们想要的执行计划的这些HINTS,Oracle可以存储这些HINTS,我们称之为OUTLINES。通过STORE OUTLINES可以使得我们拥有以后产生相同执行计划的能力,也就是使我们拥有了稳定执行计划的能力。

3.1      Oracle Hints的使用

Eg: alter session enable dml parallel

insert /*+parallel(xxxx,4) */ into xxxx select /*+parallel(a) */ * from xxx a;

Hints的具体用户请自己查询相关资料。。。。。。

http://blog.csdn.net/runming918/article/details/8900750

3.2      Oracle 收集统计更新信息

也许我们会有疑问,假如稳定了执行计划,那还搜集统计信息干吗?这是因为几个原因造成的,首先,现在的执行计划对于未来发生了变化的数据未必就是合适的,存在着当前的执行计划不满足未来数据的变化后的效率,而新的统计信息的情况下所产生的执行计划也并不是全部都合理的。那这个时候,我们可以采用新搜集的统计信息,但是却对新统计信息下不良的执行计划采用Oracle提供的执行计划稳定性这个能力固定执行计划,这样结合起来我们可以建立满意的高效的数据库运行环境。

我们还需要关注的一个东西,Oracle提供的dbms_stats包除了具有搜集统计信息的能力,还具有把数据库中统计信息(statistics)export/import的能力,还具有只搜集统计信息而使得统计信息不应用于数据库的能力(把统计信息搜集到一个特定的表中而不是立即生效),在这个基础上我们就可以把统计信息export出来再import到一个测试环境中,再运行我们的应用,在测试环境中我们观察最新的统计信息会导致哪些执行计划发生变化(DB EXPERTPlan Version Tracer是模拟不同环境并自动检查不同环境中执行计划变化的工具),是变好了还是变差了。我们可以把变差的这一部分在测试环境中使用hints或者利用工具(SQL EXPERT是在重写SQL这一领域目前最强有力的工具)产生良好的执行计划的SQL,利用这些SQL可以产生OUTLINES,然后在产品数据库应用最新的统计信息的同时移植进这些OUTLINES

猜你喜欢

转载自lylan.iteye.com/blog/2015744