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



一般来说,有如下几种获取执行计划的方式:

1、AUTOTRACE方式

AUTOTRACEOracle自带的客户端工具SQL*Plus的一个特性。启用AUTOTRACE后,SQL*Plus会自动收集执行过的SQL语句的执行计划、性能统计数据等,并在语句执行结束后显示在SQL*Plus中。

DBA用户可以直接使用AUTOTRACE功能但是如果用户没有DBA权限,那么需要在SYS用户下执行plustrce.sql脚本,自动创建PLUSTRACE角色,再把PLUSTRACE权限赋给普通用户即可。

$ORACLE_HOME/sqlplus/admin/plustrce.sql

GRANT PLUSTRACE TO USER_LHR;

另外,若启用AUTOTRACE报“SP2-0611”的错误,则可以执行utlxplan.sql脚本来创建表PLAN_TABLE,如下所示:

SQL> set autot on

SP2-0613: 无法验证 PLAN_TABLE 格式或实体

SP2-0611: 启用EXPLAIN报告时出错

SQL> @?/rdbms/admin/utlxplan.sql

在执行如下脚本后,每个用户(包括以后新建的用户)都可以使用AUTOTRACE命令:

@?/rdbms/admin/utlxplan.sql

CREATE PUBLIC SYNONYM PLAN_TABLE FOR PLAN_TABLE;

GRANT ALL ON PLAN_TABLE TO PUBLIC;

@?/sqlplus/admin/plustrce.sql

GRANT PLUSTRACE TO PUBLIC;

AUTOTRACE的语法如下所示:

SET AUTOTRACE {OFF|ON|TRACEONLY} [EXPLAIN] [STATISTICS]

其中,AUTOTRACE可简写为AUTOTTRACEONLY可简写为TRACEEXPLAIN可简写为EXPSTATISTICS可简写为STAT

SQL> SET AUTOT ON

SQL> SELECT COUNT(*) FROM PLAN_TABLE;

COUNT(*)

----------

68

Execution Plan

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

Plan hash value: 1751138260

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

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

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

|   0 | SELECT STATEMENT   |             |     1 |     3   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |             |     1 |            |          |

|   2 |   TABLE ACCESS FULL| PLAN_TABLE$ |    68 |     3   (0)| 00:00:01 |

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

Note

-----

- dynamic sampling used for this statement

Statistics

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

27  recursive calls

0  db block gets

15  consistent gets

0  physical reads

0  redo size

515  bytes sent via SQL*Net to client

487  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

AUTOTRACE STATISTICS含义见下表:

序号

列名

解释

1

recursive calls

递归调用表示执行SQL的时候的产生的递归调用的次数Oracle在执行SQL的时候,有时候会生成很多额外的SQL语句,这个就称为递归调用。这个参数和访问数据字典的次数有很大的关系,一般来说,这个参数值不会很大。

2

db block gets

DB块取,表示当前读。在发生INSERTDELETEUPDATESELECT FOR UPDATE的时候,数据库缓冲区中的数据库块的个数。在SELECT语句中一般为0

3

consistent gets

一致性读,表示除了SELECT FOR UPDATE的时候,从数据库缓冲区中读取的数据块的个数(注意,实际上并不是块的个数),可能会读取回滚段的信息,一般来说,逻辑读Logical Reads= 当前读(db block gets+ 一致性读(consistent gets

4

physical reads

物理读,在执行SQL的过程中,从硬盘上读取的数据块个数。

5

redo size

SQL语句在执行过程中产生的Redo的字节数。

6

bytes sent via SQL*Net to client

服务器利用SQL*Net发送客户端的字节数

7

bytes received via SQL*Net from client

服务器利用SQL*Net从客户端接收的字节数

8

SQL*Net roundtrips to/from client

从客户端发送和接收的SQL*Net消息的总数,包括从多行的结果集中提取的往返消息。

9

sorts (memory)

在内存执行的排序次数

10

sorts (disk)

在磁盘上执行的排序次数,如果内存空间不足,那么会使用磁盘空间

11

rows processed

更改或选择返回的行数。

2、EXPLAIN PLAN FOR方式

SQL> EXPLAIN PLAN FOR SELECT * FROM T017_LHRO;

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT

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

Plan hash value: 3200443156

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

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

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

|   0 | SELECT STATEMENT  |           |  1363 |   177K|     9   (0)| 00:00:01 |

|   1 |  TABLE ACCESS FULL| T017_LHRO |  1363 |   177K|     9   (0)| 00:00:01 |

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

3、DBMS_XPLAN.DISPLAY_CURSOR方式

SYS@RAC2LHR1> SELECT * FROM V$VERSION WHERE ROWNUM<2;

BANNER

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

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SYS@RAC2LHR1> SELECT ENAME,DNAME,LOC

2   FROM SCOTT.EMP E,SCOTT.DEPT D

3  WHERE E.DEPTNO = D.DEPTNO

4  AND E.EMPNO = 7788;

ENAME      DNAME          LOC

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

SCOTT      RESEARCH       DALLAS

如果不传递任何参数给DISPLAY_CURSOR函数,那么默认显示当前会话最后一条SQL语句的执行计划,如下所示:

SYS@RAC2LHR1> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL));

PLAN_TABLE_OUTPUT

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

SQL_ID  315xan8zgvtbm, child number 0

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

SELECT ENAME,DNAME,LOC  FROM SCOTT.EMP E,SCOTT.DEPT D WHERE E.DEPTNO =

D.DEPTNO AND E.EMPNO = 7788

Plan hash value: 1674520956

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

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

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

|   0 | SELECT STATEMENT             |         |       |       |     2 (100)|          |

|   1 |  NESTED LOOPS                |         |     1 |    33 |     2   (0)| 00:00:01 |

|   2 |   TABLE ACCESS BY INDEX ROWID| EMP     |     1 |    13 |     1   (0)| 00:00:01 |

|*  3 |    INDEX UNIQUE SCAN         | PK_EMP  |     1 |       |     0   (0)|          |

|   4 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |

|*  5 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)|          |

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

Predicate Information (identified by operation id):

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

3 - access("E"."EMPNO"=7788)

5 - access("E"."DEPTNO"="D"."DEPTNO")

24 rows selected.

传递SQL_ID以及FORMAT参数给DISPLAY_CURSOR函数,并配合修饰符控制执行计划的输出,如下所示:

SYS@RAC2LHR1> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('315XAN8ZGVTBM',NULL,'ALL'));

PLAN_TABLE_OUTPUT

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

SQL_ID  315xan8zgvtbm, child number 0

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

SELECT ENAME,DNAME,LOC  FROM SCOTT.EMP E,SCOTT.DEPT D WHERE E.DEPTNO =

D.DEPTNO AND E.EMPNO = 7788

Plan hash value: 1674520956

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

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

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

|   0 | SELECT STATEMENT             |         |       |       |     2 (100)|          |

|   1 |  NESTED LOOPS                |         |     1 |    33 |     2   (0)| 00:00:01 |

|   2 |   TABLE ACCESS BY INDEX ROWID| EMP     |     1 |    13 |     1   (0)| 00:00:01 |

|*  3 |    INDEX UNIQUE SCAN         | PK_EMP  |     1 |       |     0   (0)|          |

|   4 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |

|*  5 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)|          |

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

Query Block Name / Object Alias (identified by operation id):

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

1 - SEL$1

2 - SEL$1 / E@SEL$1

3 - SEL$1 / E@SEL$1

4 - SEL$1 / D@SEL$1

5 - SEL$1 / D@SEL$1

Predicate Information (identified by operation id):

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

3 - access("E"."EMPNO"=7788)

5 - access("E"."DEPTNO"="D"."DEPTNO")

Column Projection Information (identified by operation id):

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

1 - "ENAME"[VARCHAR2,10], "DNAME"[VARCHAR2,14], "LOC"[VARCHAR2,13]

2 - "ENAME"[VARCHAR2,10], "E"."DEPTNO"[NUMBER,22]

3 - "E".ROWID[ROWID,10]

4 - "DNAME"[VARCHAR2,14], "LOC"[VARCHAR2,13]

5 - "D".ROWID[ROWID,10]

42 rows selected.

利用STATISTICS_LEVEL或/*+ GATHER_PLAN_STATISTICS*/可以知道表访问的次数,也可以查看真实执行计划并获得统计信息。如下所示:

SET SERVEROUTPUT OFF

ALTER SESSION SET STATISTICS_LEVEL=ALL;

执行SQL语句

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ADVANCED ALLSTATS LAST'));

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(SQL_ID =>'',CURSOR_CHILD_NO =>1,FORMAT => 'ADVANCED ALLSTATS'));

其中参数SQL_ID为父游标,如果为NULL那么表示显示该会话之前的SQL执行计划。CURSOR_CHILD_NO为子游标的序号,默认为0,如果设定为NULL那么所有该父游标下所有的子游标的执行计划都将返回。参数FORMAT指定要显示哪些信息,常用的有:IOSTATSI/O信息显示)、ALLSTATSI/O信息显示+PGA信息)、ADVANCED(显示所有统计信息)、IOSTATS LASTALLSTATS LAST(只显示最后一次执行的统计信息)。默认值TYPICAL只能显示一个普通的执行计划,不能显示出实际返回的行。

?这种方式也是SQL调优中常用的方法,但使用该方法的前提是如下个条件必须同时满足:

① 一般在会话级别设置参数STATISTICS_LEVELALL也可以使/*+ GATHER_PLAN_STATISTICS*/提示。

② 若DBMS_XPLAN.DISPLAY_CURSOR中的入参SQL_ID输入值为NULL的话,则SERVEROUTPUT必须设置为OFFSET SERVEROUTPUT OFF,否则类似如下的错误:

PLAN_TABLE_OUTPUT

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

SQL_ID  9m7787camwh4m, child number 0

begin :id := sys.dbms_transaction.local_transaction_id; end;

NOTE: cannot fetch plan for SQL_ID: 9m7787camwh4m, CHILD_NUMBER: 0

Please verify value of SQL_ID and CHILD_NUMBER;

It could also be that the plan is no longer in cursor cache (check v$sql_plan)

若为具体SQL_ID的值的话,则无论SERVEROUTPUT的值如何都可以正常执行。

示例如下所示:

SYS@RAC2LHR1> SHOW PARAMETER STATISTICS_LEVEL

NAME                                 TYPE        VALUE

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

statistics_level                     string      TYPICAL

SYS@RAC2LHR1> ALTER SESSION SET STATISTICS_LEVEL=ALL;

Session altered.

SYS@RAC2LHR1> SHOW SERVEROUTPUT

serveroutput OFF

SYS@RAC2LHR1> SELECT ENAME,DNAME,LOC

2   FROM SCOTT.EMP E,SCOTT.DEPT D

3   WHERE E.DEPTNO = D.DEPTNO

4    AND E.EMPNO = 7369;

ENAME      DNAME          LOC

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

SMITH      RESEARCH       DALLAS

SYS@RAC2LHR1> SET PAGESIZE 0

SYS@RAC2LHR1> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'IOSTATS LAST -PREDICATE -NOTE'));

SQL_ID  g3mx9hdyrhus7, child number 0

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

SELECT ENAME,DNAME,LOC  FROM SCOTT.EMP E,SCOTT.DEPT D  WHERE E.DEPTNO =

D.DEPTNO   AND E.EMPNO = 7369

Plan hash value: 1674520956

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

| Id  | Operation                    | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |

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

|   0 | SELECT STATEMENT             |         |      1 |        |      1 |00:00:00.01 |       4 |

|   1 |  NESTED LOOPS                |         |      1 |      1 |      1 |00:00:00.01 |       4 |

|   2 |   TABLE ACCESS BY INDEX ROWID| EMP     |      1 |      1 |      1 |00:00:00.01 |       2 |

|   3 |    INDEX UNIQUE SCAN         | PK_EMP  |      1 |      1 |      1 |00:00:00.01 |       1 |

|   4 |   TABLE ACCESS BY INDEX ROWID| DEPT    |      1 |      1 |      1 |00:00:00.01 |       2 |

|   5 |    INDEX UNIQUE SCAN         | PK_DEPT |      1 |      1 |      1 |00:00:00.01 |       1 |

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

SYS@RAC2LHR1> SELECT /*+ GATHER_PLAN_STATISTICS */ENAME,DNAME,LOC

2   FROM SCOTT.EMP E,SCOTT.DEPT D

3   WHERE E.DEPTNO = D.DEPTNO

4   AND E.EMPNO = 7369;

SMITH      RESEARCH       DALLAS

SYS@RAC2LHR1> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'BASIC LAST ALLSTATS'));

EXPLAINED SQL STATEMENT:

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

SELECT /*+ GATHER_PLAN_STATISTICS */ ENAME,DNAME,LOC  FROM SCOTT.EMP

E,SCOTT.DEPT D  WHERE E.DEPTNO = D.DEPTNO  AND E.EMPNO = 7369

Plan hash value: 1674520956

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

| Id  | Operation                    | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |

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

|   0 | SELECT STATEMENT             |         |      1 |        |      1 |00:00:00.01 |       4 |

|   1 |  NESTED LOOPS                |         |      1 |      1 |      1 |00:00:00.01 |       4 |

|   2 |   TABLE ACCESS BY INDEX ROWID| EMP     |      1 |      1 |      1 |00:00:00.01 |       2 |

|*  3 |    INDEX UNIQUE SCAN         | PK_EMP  |      1 |      1 |      1 |00:00:00.01 |       1 |

|   4 |   TABLE ACCESS BY INDEX ROWID| DEPT    |      1 |      1 |      1 |00:00:00.01 |       2 |

|*  5 |    INDEX UNIQUE SCAN         | PK_DEPT |      1 |      1 |      1 |00:00:00.01 |       1 |

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

Predicate Information (identified by operation id):

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

3 - access("E"."EMPNO"=7369)

5 - access("E"."DEPTNO"="D"."DEPTNO")

4、其它跟踪方法

除了上述方法外,还可以通过其它一些途径获取到语句的执行计划,例如1004610053事件等,但在这些方法所产生的数据里,执行计划通常仅是辅助解决问题的一个部分,而非重点。

5、第三方工具

利用第三方工具,如PL/SQL DEVTODO开发工具,在PL/SQL DEV中选定SQL后,按F5即可查看执行计划:

D:.Users.XIAOMA~1.AppData.Local.Temp.ksohtml.wps5270.tmp.jpg

此外,还可以通过写脚本从V$SQL_PLANDBA_HIST_SQL_PLANV$SQL_PLAN_MONITOR等视图中来获取执行计划。

下表对这几种获取执行计划的方法给予总结:

方法

简介

SQL语句是否真实执行过

是否真实执行计划

物理读、逻辑读、递归调用

运行时间

处理行数

表访问次数

等待事件

解析时间

set autotrace

SET AUTOTRACE OFF

此为默认值,即关闭AUTOTRACE

SET AUTOTRACE ON

包含SQL语句的执行结果、SQL语句执行结果的数量、执行计划和统计信息内容

不确定

SET AUTOTRACE ON EXPLAIN

包含SQL语句的执行结果、SQL语句执行结果的数量和执行计划

SET AUTOTRACE ON STATISTICS

包含SQL语句的执行结果、SQL语句执行结果的数量和统计信息内容

SET AUTOTRACE TRACEONLY

包含SQL执行结果的数量、执行计划和统计信息内容,但不显示SQL语句的执行结果

SET AUTOTRACE TRACEONLY EXPLAIN

EXPLAIN PLAN命令,对于SELECT语句不会执行,只显示目标SQL的执行计划,但是对于DML语句还是会执行的,而且显示SQL语句执行结果的数量和执行计划

SET AUTOTRACE TRACEONLY STATISTICS

显示SQL语句执行结果的数量和统计信息,不显示执行计划和SQL执行结果

DBMS_XPLAN

EXPLAIN PLAN FOR

DBMS_XPLAN.DISPLAY

EXPLAIN PLAN FOR SQL语句;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL,NULL,'ADVANCED'));

不确定

STATISTICS_LEVEL=ALL

SELECT /*+GATHER_PLAN_STATISTICS*/ ...

DBMS_XPLAN.DISPLAY_CURSOR

ALTER SESSION SET STATISTICS_LEVEL=ALL ;

执行SQL

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ALLSTATS LAST'));

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&SQLID',0,'BASIC LAST ALLSTATS ADVANCED'));

DBMS_XPLAN.DISPLAY_CURSOR

没有设置STATISTICS_LEVEL=ALL或没有使用/*+ GATHER_PLAN_STATISTICS*/Hint

SELECT  * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&SQLID')); --从内存得到执行计划

DBMS_XPLAN.DISPLAY_AWR

DISPLAY_AWR函数显示存储在AWR历史数据的执行计划。SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('&SQLID'));

DBMS_XPLAN.DISPLAY_SQLSET

DISPLAY_SQLSET函数显示存储在一个SQL调优集中的语句的执行计划,SQL调优集查询DBA_SQLSET_STATEMENTS,查询执行计划的SQL语句为:SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_SQLSET('&SQLSET','&SQLID',NULL,'BASIC ALLSTATS ADVANCED'));

DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE

DISPLAY_SQL_PLAN_BASELINE函数显示存储在数据字典当中SQL执行计划基线的计划。执行计划基线所属SQL的句柄名称(SQL_HANDLE)可以通过视图DBA_SQL_PLAN_BASELINES查询,查询执行计划的SQL语句为:SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE(SQL_HANDLE => ));

SQL_TRACE事件1004610053跟踪

ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT  FOREVER,LEVEL 12';

执行SQL语句

ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF';

TKPROF格式化TRACE文件

awrsqrpt.sql

@?/rdbms/admin/awrsqrpt.sql

SELECT OUTPUT FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_SQL_REPORT_HTML(V_DBID,V_INST_ID,V_MIN_SNAP_ID,V_MAX_SNAP_ID,V_SQLID));

SQL实时监控特性:DBMS_SQLTUNE.REPORT_SQL_MONITOR

SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR('&SQLID') FROM DUAL ;

SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>'&SQLID',TYPE=>'ACTIVE',REPORT_LEVEL=>'ALL') AS REPORT FROM DUAL;

其它工具

利用第三方工具,如PL/SQL DEVTODO等开发工具,在PL/SQL DEV中选定SQL后,按F5即可查看执行计划

不确定

对于这几种获取执行计划的方法有如下结论:

① 若目标SQL需要执行很长时间才能返回结果,则推荐使用EXPLAIN PLAN FOR来获取执行计划。

② 若要查询目标SQL的所有子游标的执行计划,则推荐使用DBMS_XPLAN.DISPLAY_CURSOR('&SQLID', NULL,'ADVANCED ALLSTATS')或awrsqrpt.sql来获取执行计划。

③ 若要分析SQL语句的内部调用详情,则推荐使用10046事件。

④ 若想确保看到真实的执行计划,则不能使用EXPLAIN PLAN FORSET AUTOTRACE TRACEONLY EXPLAIN。

⑤ 若想获取到表的访问次数,则推荐/*+ GATHER_PLAN_STATISTICS*/。

⑥ 若数据库版本大于10g,则对执行时间较长的SQL语句推荐使用SQL实时监控特性查看html报告。

查看执行计划常用方法

1explain plan命令

2DBMS_XPLAN

3AUTOTRACE开关

410046事件

510053事件

6AWR SQL报告
7)PL/SQL工具直接F5

1、 explain plan(相当于PL/SQLF5

explain plan for select*fromdual;

select*from table(dbms_xplan.display);

注:相关表plan_table$是一个on commit preserve rows的global temporary table。

2、 DBMS_XPLAN

方法1:配合explain plan使用

explain plan for select*fromdual;

select*from table(dbms_xplan.display);

方法2:跟在执行语句后面,‘advanced’比‘all’多显示了“Outline Data”内容

set linesize 800

set pagesize 900

col plan_table_output for a200

select*from table(dbms_xplan.display_cursor(null,null,'advanced'));

方法3:只要目标SQL的执行计划所在的Child Cursor还没有被age outShared Pool,就可以使用该方法查看SQL执行计划

selectsql_text, sql_id, hash_value, child_number

fromv$sql

wheresql_textlike 'select count(*) from sh.customers%';

select*from table(dbms_xplan.display_cursor('sql_id/hash_value',

child_cursor_number,'advanced'));

方法4:用于查看指定SQL的所有历史执行计划,没有谓词信息

--目标SQL可能有多个Child Cursor,即多个执行计划

selectsql_text, sql_id,version_count, executions

fromv$sqlarea

wheresql_textlike 'select count(*) from sh.customers%';

select*from table(dbms_xplan.display_awr('sql_id'));

注:Oracle把执行计划采样数据从V$sql_plan搬到AWR Repository基表wrh$_sql_plan中没有保留谓词信息的记录。

3、AUTOTRACE开关

可以额外观察到目标SQL执行时所耗费的物理读、逻辑读、产生redo数量以及排序的数量。(statistics

setoutotraceon;

setoutotraceoff;

setoutotrace traceonly;--不现实SQL执行结果

setoutotrace traceonlyexplain;

setoutotrace traceonlystatistics;

4、 10046事件与tkprof命令

明确显示了目标SQL实际执行计划中每一个执行步骤所消耗的逻辑读、物理读和花费的时间。(USER_DUMP_DEST目录下生成trace文件。

--打开

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

oradebug event 10046 trace name context forever,level 12;

--关闭

alter session set events '10046 trace name context off';

oradebug event 10046 trace name context off;

注:level12表示trace文件中还包含目标SQL所使用的绑定变量的值以及该session所经历的等待事件。

--操作步骤--

aSQL> oradebug setmypid;

bSQL> oradebug event10046 trace name contextforever,level 12;

cSQL>select count(*)fromdual;

dSQL> oradebug tracefile_name;

/oracle/app/oracle/diag/rdbms/test/test/trace/test_ora_4288.trc

eSQL> oradebug event10046 trace name context off;

f[oracle@test~]$tkprof /oracle/app/oracle/diag/rdbms/test

/test/trace/test_ora_4288.trc /oracle/test_ora_4288_tkprof.trc

5、10053事件

6、AWR SQL报告、Statspack报告

7、一些现成的脚本(display_cursor_9i.sql)

8、 PL/SQL工具直接F5



原文地址:http://blog.itpub.net/17203031/viewspace-704626

SQL调优是很多Oracle DBA和开发人员的重要工作。一个高效的SQL改写调优,可以大幅度优化执行计划,提高执行效率,进而增强关键用例模块的可用性和满意度。

进行SQL调优中不可缺少的操作就是获取指定SQL的执行计划。在目前的Oracle版本中,有很多可以使用的执行计划获取方法。本篇就加以总结,供需要的朋友不时之需。

1、方便易用的explain plan

Explain plan命令在Oracle中,可以对后面的SQL语句进行直接的解析,将执行计划保存在一个plan_table的中间表中。之后通过dbms_xplan包的方法进行获取。

ü确定plan_table的安装

使用explain plan命令的一个前提就是系统中存在plan_table数据表。如果没有的话,需要进行脚本调用安装。

--如果不存在,就生成

SQL> @?/rdbms/admin/catplan.sql

程序包体已创建。

没有错误。

这里注意两个细节:

首先,调用脚本中的?表示ORACLE_HOME目录。如果是使用sqlplus工具,可以直接使用?代指该目录。其他如PL/SQL Developer第三方工具不支持;

其次,如果是Oracle 10g以上的版本,使用脚本名称为catplan.sql。如果是如9i的版本,使用脚本名称为utlxplan.sql。如果在高版本Oracle上使用低版本的plan_table结构,可能在生成执行计划中报错“Plan Table version too old”错误。

ü使用explain plan for命令生成执行计划并显示

SQL> set linesize 10000;

SQL> set wrap off;

SQL> set pagesize 10000;

SQL> explain plan for select * from scott.emp where empno=7839;

已解释。

之后使用dbms_xplan工具包将生成的执行计划展示出。

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

Plan hash value: 2949544139

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

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

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

|   0 | SELECT STATEMENT            |        |     1 |    35 |     1   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    35 |     1   (0)| 00:00:01 |

|*  2 |   INDEX UNIQUE SCAN         | PK_EMP |     1 |       |     0   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("EMPNO"=7839)

已选择14行。

该语句显示出索引执行计划。

ü显示详细执行计划信息

上面直接调用,是显示出分析的SQL最简单的执行计划。可以通过设置format参数,显示出关于计划的更详细信息。

SQL> select * from table(dbms_xplan.display(null,null,'advanced'));

PLAN_TABLE_OUTPUT

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

Plan hash value: 2949544139

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

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

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

|   0 | SELECT STATEMENT            |        |     1 |    35 |     1   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    35 |     1   (0)| 00:00:01 |

|*  2 |   INDEX UNIQUE SCAN         | PK_EMP |     1 |       |     0   (0)| 00:00:01 |

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

Query Block Name / Object Alias (identified by operation id):

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

1 - SEL$1 / EMP@SEL$1

2 - SEL$1 / EMP@SEL$1

Outline Data

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

/*+

BEGIN_OUTLINE_DATA

INDEX(@"SEL$1" "EMP"@"SEL$1" ("EMP"."EMPNO"))

OUTLINE_LEAF(@"SEL$1")

ALL_ROWS

OPTIMIZER_FEATURES_ENABLE('10.2.0.1')

IGNORE_OPTIM_EMBEDDED_HINTS

END_OUTLINE_DATA

*/

Predicate Information (identified by operation id):

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

2 - access("EMPNO"=7839)

Column Projection Information (identified by operation id):

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

1 - "EMPNO"[NUMBER,22], "EMP"."ENAME"[VARCHAR2,10],

"EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22], "EMP"."HIREDATE"[DATE,7],

"EMP"."SAL"[NUMBER,22], "EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]

2 - "EMP".ROWID[ROWID,10], "EMPNO"[NUMBER,22]

已选择41行。

添加了format参数,Oracle将更加详细的执行计划信息返回,包括Outline信息、结果集合映射等内容。

üExplain plan for细节

Explain plan for使用比较方便,特别是可以支持在pl/sql developer等第三方开发工具中使用的特性,比较吸引人。不过,explain plan在使用的时候,要注意一些潜在问题:

首先,explain plan for是单纯对SQL语句进行优化器分析,获取产生到的执行计划。这个过程中,并没有真正执行。所以,生成的执行计划有时候会有bug,而且进行统计的信息情况没有autotrace高;

其次,explain plan for由于只是对执行计划进行估计。所以在有绑定变量的SQL时,生成的执行计划并不准确;

2、获取“刚刚”的执行计划display_cursor

使用dbms_xplan包,还可以获取刚刚执行过的SQL执行计划信息。

SQL>  select * from scott.emp where empno=7900;

EMPNO ENAME      JOB              MGR HIREDATE              SAL       COMM     DEPTNO

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

7900 JAMES      CLERK           7698 03-12-81            950                    30

SQL> select * from table(dbms_xplan.display_cursor);//获取刚刚的执行计划;

PLAN_TABLE_OUTPUT

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

SQL_ID  66nkfdw21rc9j, child number 0

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

select * from scott.emp where empno=7900

Plan hash value: 2949544139

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

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

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

|   0 | SELECT STATEMENT            |        |       |       |     1 (100)|          |

|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    35 |     1   (0)| 00:00:01 |

|*  2 |   INDEX UNIQUE SCAN         | PK_EMP |     1 |       |     0   (0)|          |

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

Predicate Information (identified by operation id):

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

2 - access("EMPNO"=7900)

已选择19行。

直接调用display_cursor,不指定sql_id,就可以将刚刚当前会话执行的SQL命令执行计划从library cache中抽取出来。

注意:display_cursor也支持format参数,可以进行详细执行计划信息的抽取。

此外还有一点,就是这种方法获取刚刚执行过的SQL执行计划,只能在sqlplus或者sqlplusw上使用。如果是pl/sql developer等第三方工具,可能不适用。

(注意:在pl/sql developer下使用存在问题)

SQL> select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

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

SQL_ID  9m7787camwh4m, child number 0

begin :id := sys.dbms_transaction.local_transaction_id; end;

NOTE: cannot fetch plan for SQL_ID: 9m7787camwh4m, CHILD_NUMBER: 0

Please verify value of SQL_ID and CHILD_NUMBER;

It could also be that the plan is no longer in cursor cache (check v$sql_p

8 rows selected

3autotrace工具使用

本人以为autotrace工具是获取执行计划信息较为完整的工具。优势在于使用该工具可以获取到执行SQL过程中的读写、调用递归和排序分组消耗。

在之前的Blog中,笔者已经撰写过一篇关于autotrace较为详细的文章,有兴趣的读者可以参考:《Autotrace工具使用——小工具,大用场》(http://space.itpub.net/17203031/viewspace-686535)。

在下篇中,我们会介绍直接从shared_pool中抽取执行计划,和从AWR报告库中抽取。最后介绍使用10046事件跟踪执行计划。

上篇中,我们介绍了几种获取执行计划的方法。本篇我们继续探讨其他获取到执行计划详细信息的方法。

4、从shared_pool中直接抽取执行计划

我们执行过的SQL,在Oracle中会将执行计划缓存一段时间,就在shared_poollibrary cache中。这是真实使用的执行计划,我们可以使用手段加以抽取展现。

shared_pool中,执行计划主要是以shared cursor方式进行保存,也就是父子游标方式。一个父游标parent cursor联动若干child cursor,每个child cursor对应一个单独的执行计划。

SQL> select /*+ exp_demo */* from scott.emp where empno=7323;

未选定行

v$sqlv$sqlarea中获取到对应的计划。

//v$sqlarea中获取到父游标;

SQL> select substr(sql_text,1,20), sql_id, address, version_count,executions from v$sqlarea where sql_text like 'select /*+ exp_demo */*%';

SUBSTR(SQL_TEXT,1,20)                    SQL_ID        ADDRESS  VERSION_COUNT EXECUTIONS

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

select /*+ exp_demo                a78616x8uja32 2254266C             1          1

//v$sql中获取到子游标;

SQL> select sql_id, child_number, executions from v$sql where sql_id='a78616x8uja32';

SQL_ID        CHILD_NUMBER EXECUTIONS

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

a78616x8uja32            0          1

获取到sql_idchild_number之后,就可以使用dbms_xplay.display_cursor方法进行抽取。

SQL> select * from table(dbms_xplan.display_cursor('a78616x8uja32',0));

PLAN_TABLE_OUTPUT

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

SQL_ID  a78616x8uja32, child number 0

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

select /*+ exp_demo */* from scott.emp where empno=7323

Plan hash value: 2949544139

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

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

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

|   0 | SELECT STATEMENT            |        |       |       |     1 (100)|          |

|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    35 |     1   (0)| 00:00:01 |

|*  2 |   INDEX UNIQUE SCAN         | PK_EMP |     1 |       |     0   (0)|          |

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

Predicate Information (identified by operation id):

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

2 - access("EMPNO"=7323)

已选择19行。

这种方式获取到的执行计划是最准确的执行计划。同样display_cursor也是支持format参数。当使用绑定变量时,还可以抽取出bind peeking的变量取值。

5、从AWR报告库中获取执行计划

直接从shared_pool中获取执行计划,虽然是最准确的但存在实效的问题。如果执行一段时间之后,执行计划shared cursor会由于LRU算法被剔除shared_pool。或者因为环境变化,让执行计划重新生成。所以,很多时候,我们需要更多时间进行SQL分析。

这时候我们就需要AWRAutomatic Workload Repository)的镜像snapshot功能。每个固定时间,Oracle AWR会将系统状况已快照的方式保存下来。这个过程中,也就会将这些shared pool执行计划保存下来。

我们通常使用AWR报告时,发现问题SQL的情况。如下:

17203031_201108111921481.jpg

我们发现sql_id=’ 4x74bc7r4npq4’SQL存在执行时间长的问题。此时,该SQL可能已经被置换出SGA,所以可以使用dbms_xplandisplay_awr方法抽取AWR存储获取执行计划。

SQL> select * from table(dbms_xplan.display_awr('4x74bc7r4npq4',format => 'advanced'));

PLAN_TABLE_OUTPUT

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

SQL_ID 4x74bc7r4npq4

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

select ticket0_.SEQ_NUMBER as SEQ1_324_, ticket0_.VERSION as

VERSION324_, ticket0_.CREATE_DATE as CREATE3_324_, ticket0_.CREATE_USER

(篇幅原因,有删节……

ticket0_.WEB_SALE_I as WEB121_324_ from BSD_TICKET ticket0_ where

TDNR=:1 and TACN=:2

Plan hash value: 3282229029

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

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

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

|   0 | SELECT STATEMENT  |            |       |       | 11382 (100)|          |

|   1 |  TABLE ACCESS FULL| BSD_TICKET |     1 |   582 | 11382   (1)| 00:02:17 |

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

Query Block Name / Object Alias (identified by operation id):

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

1 - SEL$1 / TICKET0_@SEL$1

Outline Data

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

/*+

BEGIN_OUTLINE_DATA

IGNORE_OPTIM_EMBEDDED_HINTS

OPTIMIZER_FEATURES_ENABLE('11.2.0.1')

DB_VERSION('11.2.0.1')

ALL_ROWS

OUTLINE_LEAF(@"SEL$1")

FULL(@"SEL$1" "TICKET0_"@"SEL$1")

END_OUTLINE_DATA

*/

Peeked Binds (identified by position): //绑定变量时用的bind peeking值;

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

1 - :1 (VARCHAR2(30), CSID=873): '1661663695'

2 - :2 (VARCHAR2(30), CSID=873): '618'

97 rows selected

6、使用10046事件跟踪

传统获取执行计划的方法,是使用10046跟踪事件。通过开启事件跟踪,生成跟踪trace文件。最后通过分析跟踪文件,定位到真实的执行计划。分别按照如下步骤完成:

ü        开启10046跟踪事件,执行诊断SQL

SQL> alter session set events='10046 trace name context forever, level 12';

Session altered

SQL> select * from scott.emp where empno=7323;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO

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

ü        定位跟踪文件

由于使用的是Oracle 10g,笔者使用自定义的函数进行获取。

SQL> select f_get_trace_name from dual;

F_GET_TRACE_NAME

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

C:\TOOL\ORACLE\ORACLE\PRODUCT\10.2.0\ADMIN\OTS\UDUMP\ots_ora_3388.trc

说明:如果是在Oracle 11g,可以检索视图v$diag_info来获取当前会话的诊断文件名称。

ü        使用tkprof工具进行跟踪文件处理

由于.trc文件大都是粗格式文档,不宜于阅读。所以可以使用tkprof工具对跟踪文件进行处理。

D:\>tkprof ots_ora_3388.trc result.txt

TKPROF: Release 10.2.0.1.0 - Production on星期三810 10:04:34 2011

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

从处理结果文件result.txt中,我们可以找到对应SQL的执行计划信息。

select *

from

scott.emp where empno=7323

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.03       0.02          0          0          0           0

Execute      1      0.00       0.00          0          0          0           0

Fetch        1      0.00       0.00          0          1          0           0

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

total        3      0.03       0.02          0          1          0           0

Misses in library cache during parse: 1

Optimizer mode: ALL_ROWS

Parsing user id: SYS

Rows     Row Source Operation

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

0  TABLE ACCESS BY INDEX ROWID EMP (cr=1 pr=0 pw=0 time=45 us)

0   INDEX UNIQUE SCAN PK_EMP (cr=1 pr=0 pw=0 time=30 us)(object id 51152)

Elapsed times include waiting on following events:

Event waited on                             Times   Max. Wait  Total Waited

----------------------------------------   Waited  ----------  ------------

SQL*Net message to client                       2        0.00          0.00

SQL*Net message from client                     2        0.03          0.03

该种方法比较复杂,但是获取到的信息很精确。同时,也可以获取到关于SQL处理三阶段(ParseExecuteFetch)的相应处理内容。

7、结论

SQL执行计划是我们研究Oracle、研究Oracle优化器的一个重要手段工具。本篇系列关注如何获取SQL的执行计划,列举出六种详细的手段和方法。不同方法均有其优缺点和适应环境,选择正确的方法才可以起到最好的效果。

fj.pngpic.jpg



About Me

...............................................................................................................................

● 本文整理自网络

● 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/

● 本文博客园地址:http://www.cnblogs.com/lhrbest

● 本文pdf版及小麦苗云盘地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 数据库笔试面试题库及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● QQ群:230161599微信群:私聊

● 联系我请加QQ好友(646634621),注明添加缘由

● 于 2017-04-28 09:00 ~ 2017-04-30 22:00 在魔都完成

● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解

● 版权所有,欢迎分享本文,转载请保留出处

...............................................................................................................................

拿起手机使用微信客户端扫描下边的左边图片来关注小麦苗的微信公众号:xiaomaimiaolhr,扫描右边的二维码加入小麦苗的QQ群,学习最实用的数据库技术。

ico_mailme_02.png DBA笔试面试讲解 欢迎与我联系

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26736162/viewspace-2136865/,如需转载,请注明出处,否则将追究法律责任。

Oracle查看执行计划的几种方法相关推荐

  1. 【转载】Oracle 查看执行计划

    来源url Oracle 查看执行计划 - 攻城猿的个人空间 - OSCHINA - 中文开源技术交流社区 一:什么是 Oracle 执行计划? 执行计划是一条查询语句在 Oracle 中的执行过程或 ...

  2. oracle怎么看一个表结构,Oracle查看表结构的几种方法

    Oracle查看表结构的几种方法 1,DESCRIBE 命令 使用方法如下: SQLgt; describe nchar_tst(nchar_tst为表名) 显示的结果如下: Oracle查看表结构的 ...

  3. oracle 执行计划 ppt,oracle查看执行计划的方法

    查看执行计划的方法 Explain Plan For SQL 不实际执行SQL语句,生成的计划未必是真实执行的计划 必须要有plan_table SQLPLUS AUTOTRACE 除set auto ...

  4. oracle查看执行计划入门

    基于Oracle的应用系统很多的性能问题都是由应用系统的SQL性能低劣引起的,因此SQL的性能优化非常重要.要分析与优化SQL的性能,一般是通过查看该SQL的执行计划,然后通过执行计划有针对性地对SQ ...

  5. oracle的解析計劃,Oracle中获取执行计划的几种方法分析

    1. 预估执行计划 - Explain PlanExplain plan以SQL语句作为输入,得到这条SQL语句的执行计划,并将执行计划输出存储到计划表中. 首先,在你要执行的SQL语句前加expla ...

  6. oracle执行计划耗费 基数 字节,Oracle 查看执行计划

    一:什么是Oracle执行计划? 执行计划是一条查询语句在Oracle中的执行过程或访问路径的描述 二:怎样查看Oracle执行计划? 这里以PLSQL为例: ①:配置执行计划需要显示的项: 工具  ...

  7. Oracle进阶篇之查看执行计划

    目录 一.查看执行计划的方式 1.1.设置autotrace 1.2.使用第三方工具 1.3.EXPLAIN PLAN FOR 二.清除SGA缓存 三.分析执行计划 3.1.创建测试表 3.2.查看执 ...

  8. oracle执行计划time单位,Oracle中查看执行计划

    方法一.通过使用工具PLSQL Developer中的Explain Plan Window窗口查看SQL执行计划.具体参考 方法二.通过SQL*PLUS中的autotrace命令查看 1.登录拥有d ...

  9. oracle如何查看执行计划

    1.直接使用sqlplus系统参数:       SQL> set autotrace on explain     SQL> select * from dual;     D     ...

最新文章

  1. 实例讲解决策树分类器
  2. mysql批量insert bug_MySQL Bug insert into on duplicate key update 语法更新 text blob 大字段导致 MySQL crash...
  3. 知乎热议:高数、线代应该成为计算机专业学习的重心吗?
  4. RegularExpressionValidator 控件用法
  5. Quartz在Spring中动态设置cronExpression
  6. SQL 中的游标实例
  7. redis数据持久化到mysql_redis 数据持久化的几种方式
  8. java面向对象三个关键字,Java 面向对象(三)static 关键字
  9. 动态规划经典例题:钢条切割
  10. handlerexceptionresolver ajax,Http请求的异常处理(草稿) (SEUG)
  11. chrome 独立安装包下载
  12. 如何使用VBS调用VBA函数
  13. c语言韦达定理求方程解,高一上韦达定理,高次,多元方程解法.doc
  14. 像人一样自然流畅地说话,下一代智能对话系统还有多长的路要走?
  15. 以字母Q为元素的创意logo设…
  16. Python实战笔记-常用知识点
  17. opencv+directshow采集视频图像
  18. pytest文档56-插件打包上传到 pypi 库
  19. 使用Maya和Substance Painter制作一辆越野赛车(1)
  20. eclipse各版本介绍

热门文章

  1. mysql数据库实验报告四
  2. kettle - get请求
  3. nginx 日志处理goaccess、shell
  4. estimateGas gas required exceeds allowance (6989519) or always failing transaction
  5. XP系统任务栏的输入法图标不见了
  6. android视频格式添加,Android添加新的视频格式--媒体库扫描
  7. 产品思维之【用户调研】
  8. 计算机英语读书笔记,大学英文读书笔记范文英语读书笔记十篇带翻译.doc
  9. 学习笔记《Python编程快速上手-让繁琐工作自动化》第五章 实践
  10. 解决使用svg时图标对不准