300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Oracle查看执行计划的几种方法

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

时间:2022-08-13 06:32:42

相关推荐

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

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

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

1、AUTOTRACE方式

AUTOTRACE是Oracle自带的客户端工具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可简写为AUTOT,TRACEONLY可简写为TRACE,EXPLAIN可简写为EXP,STATISTICS可简写为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含义见下表:

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: 343156

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

| 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指定要显示哪些信息,常用的有:IOSTATS(I/O信息显示)、ALLSTATS(I/O信息显示+PGA信息)、ADVANCED(显示所有统计信息)、IOSTATS LAST或ALLSTATS LAST(只显示最后一次执行的统计信息)。默认值TYPICAL只能显示一个普通的执行计划,不能显示出实际返回的行。

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

①一般在会话级别设置参数STATISTICS_LEVEL为ALL,也可以使用/*+ GATHER_PLAN_STATISTICS*/提示。

②若DBMS_XPLAN.DISPLAY_CURSOR中的入参SQL_ID输入值为NULL的话,则SERVEROUTPUT必须设置为OFF(SET 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

serveroutputOFF

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、其它跟踪方法

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

5、第三方工具

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

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

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

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

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

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

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

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

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

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

查看执行计划常用方法

1、explain plan(相当于PL/SQLF5

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

2、DBMS_XPLAN

方法1:配合explain plan使用

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

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

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

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

3、AUTOTRACE开关

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

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所经历的等待事件。

--操作步骤--

5、10053事件

6、AWR SQL报告、Statspack报告

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

8、 PL/SQL工具直接F5

原文地址:/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 forselect * 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 ENAMEJOBMGR HIREDATESALCOMMDEPTNO

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

7900 JAMESCLERK7698 03-12月-8195030

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

PLAN_TABLE_OUTPUT

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

SQL_ID66nkfdw21rc9j, 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_ID9m7787camwh4m, 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

3、autotrace工具使用

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

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

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

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

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

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

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

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

未选定行

从v$sql和v$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_IDADDRESSVERSION_COUNT EXECUTIONS

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

select /*+ exp_demoa78616x8uja32 2254266C11

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

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

SQL_IDCHILD_NUMBER EXECUTIONS

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

a78616x8uja3201

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

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

PLAN_TABLE_OUTPUT

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

SQL_IDa78616x8uja32, 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分析。

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

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

我们发现sql_id=’ 4x74bc7r4npq4’的SQL存在执行时间长的问题。此时,该SQL可能已经被置换出SGA,所以可以使用dbms_xplan的display_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 ENAMEJOBMGR HIREDATESALCOMM 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星期三8月10 10:04:34

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

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

select *

from

scott.emp where empno=7323

callcountcpuelapseddiskquerycurrentrows

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

Parse10.030.020000

Execute10.000.000000

Fetch10.000.000100

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

total30.030.00

Misses in library cache during parse: 1

Optimizer mode: ALL_ROWS

Parsing user id: SYS

RowsRow Source Operation

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

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

0INDEX 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 onTimesMax. WaitTotal Waited

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

SQL*Net message to client20.000.00

SQL*Net message from client20.030.03

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

7、结论

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

pic.jpg

About Me

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。