读懂执行计划有什么用呢?

  • 执行计划贯穿Oracle调优始终。

  • 了解执行计划的真实执行过程,将有助于优化。

  • 对亍Oracle的原理理解有一定帮助。

  • 读懂执行计划,SQL调优的第一步。

什么是SQL Execution Plan执行计划?

 SQL是声明型语言,她只说我要去哪里,但很少告诉你到底如何去?

 SQL语句的执行最终会落实为Oracle执行步骤的组合 =>【SQL执行计划】

查看执行计划的方法

  • SQLPLUS AUTOTRACE

  • Explain Plan For SQL

  • SQL_TRACE

  • 使用DBMS_XPLAN包

  • V$SQL和V$SQL_PLAN

  • Enterprise Manager

  • 其他第三方工具


  1. 如何使用sqlplus autotrace.

SQL> set autotrace help
Usage: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
SQL> conn scott/tiger
Connected.
SQL> set autotrace on
SP2-0618: Cannot find the Session Identifier.  Check PLUSTRACE role is enabled
SP2-0611: Error enabling STATISTICS report

普通用户要使用这个功能,必须建立plustrace角色,并且赋给该用户。Oracle已经为我们提供了这个脚本。

SQL> conn / as sysdba
Connected.
SQL> @?/sqlplus/admin/plustrce.sql
SQL> 
SQL> drop role plustrace;
drop role plustrace
          *
ERROR at line 1:
ORA-01919: role 'PLUSTRACE' does not exist


SQL> create role plustrace;

Role created.

SQL> 
SQL> grant select on v_$sesstat to plustrace;

Grant succeeded.

SQL> grant select on v_$statname to plustrace;

Grant succeeded.

SQL> grant select on v_$mystat to plustrace;

Grant succeeded.

SQL> grant plustrace to dba with admin option;

Grant succeeded.

SQL> 
SQL> set echo off

我们将plustrace角色赋予scott用户

SQL> grant plustrace to scott;

Grant succeeded.

再次执行set autotrace

SQL> conn scott/tiger
Connected.
SQL> set autotrace on
SQL> select * from dept;
    DEPTNO DNAME		LOC
---------- -------------------- ---------------------------------------
	10 ACCOUNTING		NEW YORK
	20 RESEARCH		DALLAS
	30 SALES		CHICAGO
	40 OPERATIONS		BOSTON

Execution Plan
----------------------------------------------------------
Plan hash value: 3383998547

--------------------------------------------------------------------------
| Id  | Operation	  | Name | Rows  | Bytes | Cost (%CPU)| Time	 |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |	 |     4 |    80 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| DEPT |     4 |    80 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Statistics
----------------------------------------------------------
	 65  recursive calls
	  0  db block gets
	 66  consistent gets
	  6  physical reads
	  0  redo size
	802  bytes sent via SQL*Net to client
	523  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  6  sorts (memory)
	  0  sorts (disk)
	  4  rows processed

如上,结果分三部分

查询结果集、执行计划、统计信息。

set autotrace on 后面可以跟三个类型的参数:

 traceonly -- 表示不执行真正的查询,只是把执行计划与统计信息打印出来。

 explain  -- 只打印查询结果和执行计划。

 stat    -- 只打印查询结果和统计信息。

执行计划解析:

  Id 表示每一步的编号,并不表示执行的序列号。

  Operation 表示执行步骤的名称

  Name 表示对象的名称

  Rows 表示查询结果返回的行数

  Bytes 表示返回结果集的大小

  Cost 表示执行计划的成本,用来衡量执行sql的速度,你可以把它想象成一个虚拟的时间单位。它的      计算方式比较复杂,依赖于系统的cpu、io等因素。

  Time 语句执行的耗时

统计信息解析:

  recursive calls :递归调用次数,为你执行的sql所执行的sql语句的条目

  db block gets:用当前读方式从buffer cache中读取块数

  consistent reads:用一致性读的方式从buffer cache中读取的块数。

  physical reads:物理读,从磁盘上读取了多少个块。

  redo size: sql产生的redo大小

  bytes sent via SQL*Net to client:从服务器发往客户端的字节总数

  bytes received via SQL*Net from client:客户机接受的字节数

 SQL*Net roundtrips to/from client:从客户机到服务器之间发生SQL*Net的次数

  sorts (memory):在内存中排序

  sorts (disk):磁盘中排序

  rows processed:影响数据的行数


下面我们看一个比较复杂的sql执行计划

SQL> set pagesize 200
SQL> set linesize 200
SQL> set autot on
SQL> select * from tab where rownum<=1;

TNAME											   TABTYPE		  CLUSTERID
------------------------------------------------------------------------------------------ --------------------- ----------
ACCESS$ 										   TABLE


Execution Plan
----------------------------------------------------------
Plan hash value: 3245953645

-----------------------------------------------------------------------------------
| Id  | Operation		| Name	  | Rows  | Bytes | Cost (%CPU)| Time	  |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT	|	  |	1 |   106 |	4   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY		|	  |	  |	  |	       |	  |
|*  2 |   FILTER		|	  |	  |	  |	       |	  |
|   3 |    NESTED LOOPS OUTER	|	  |	1 |   106 |	4   (0)| 00:00:01 |
|   4 |     NESTED LOOPS	|	  |	1 |    99 |	3   (0)| 00:00:01 |
|*  5 |      INDEX RANGE SCAN	| I_OBJ5  |	1 |    77 |	2   (0)| 00:00:01 |
|*  6 |      INDEX RANGE SCAN	| I_USER2 |	1 |    22 |	1   (0)| 00:00:01 |
|   7 |     TABLE ACCESS CLUSTER| TAB$	  |	1 |	7 |	1   (0)| 00:00:01 |
|*  8 |      INDEX UNIQUE SCAN	| I_OBJ#  |	1 |	  |	0   (0)| 00:00:01 |
|   9 |    NESTED LOOPS 	|	  |	1 |    29 |	2   (0)| 00:00:01 |
|* 10 |     INDEX SKIP SCAN	| I_USER2 |	1 |    20 |	1   (0)| 00:00:01 |
|* 11 |     INDEX RANGE SCAN	| I_OBJ4  |	1 |	9 |	1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM<=1)
   2 - filter("O"."TYPE#"<>4 AND "O"."TYPE#"<>5 AND "O"."TYPE#"<>7 AND
	      "O"."TYPE#"<>8 AND "O"."TYPE#"<>9 AND "O"."TYPE#"<>10 AND "O"."TYPE#"<>11
	      AND "O"."TYPE#"<>12 AND "O"."TYPE#"<>13 AND "O"."TYPE#"<>14 AND
	      "O"."TYPE#"<>22 AND "O"."TYPE#"<>87 AND "O"."TYPE#"<>88 OR
	      BITAND("U"."SPARE1",16)=0 OR ("O"."TYPE#"=4 OR "O"."TYPE#"=5) AND
	      (SYS_CONTEXT('userenv','current_edition_name')='ORA$BASE' AND
	      "U"."TYPE#"<>2 OR "U"."TYPE#"=2 AND "U"."SPARE2"=TO_NUMBER(SYS_CONTEXT('use
	      renv','current_edition_id')) OR  EXISTS (SELECT 0 FROM SYS."USER$"
	      "U2",SYS."OBJ$" "O2" WHERE "O2"."OWNER#"="U2"."USER#" AND "O2"."TYPE#"=88
	      AND "O2"."DATAOBJ#"=:B1 AND "U2"."TYPE#"=2 AND
	      "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_id')))))
   5 - access("O"."SPARE3"=USERENV('SCHEMAID') AND "O"."TYPE#">=2 AND
	      "O"."LINKNAME" IS NULL AND "O"."TYPE#"<=5)
       filter("O"."TYPE#"<=5 AND "O"."TYPE#">=2 AND "O"."LINKNAME" IS NULL)
   6 - access("O"."OWNER#"="U"."USER#")
   8 - access("O"."OBJ#"="T"."OBJ#"(+))
  10 - access("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('usere
	      nv','current_edition_id')))
       filter("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('usere
	      nv','current_edition_id')))
  11 - access("O2"."DATAOBJ#"=:B1 AND "O2"."TYPE#"=88 AND
	      "O2"."OWNER#"="U2"."USER#")


Statistics
----------------------------------------------------------
	  0  recursive calls
	  0  db block gets
	153  consistent gets
	  0  physical reads
	  0  redo size
	675  bytes sent via SQL*Net to client
	523  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	  1  rows processed

这个执行计划,不单复杂,而且多出了一块

Predicate Information (identified by operation id):

前面的序号,和执行计划中的id对应。filter表示表过滤条件,access表示索引过滤。

执行计划到底该怎么解读呢?

我们先把执行计划以‘树’的形式画出来。

从0开始,用缩进表示父子关系。

  0的儿子为1

  1的儿子为2

  2的儿子为3和9

  3的儿子为4和7

  4的儿子为5,6

  7的儿子为8

  9的儿子为10,11

如下图:

wKioL1XUHVKTsPIkAACpFvoQlHk730.jpg

正确的计划树形图解析顺序

树形图的解析过程:

1.从顶部开始。

2.在树中向左下移,直至到达左节点(没有子节点的节点)。首先执行此节点。

3.查看此行源的同级行源。接下来执行这些行源。

4.执行子行源后,接着执行父行源。

5.在树中不断上移,直至用完所有行源为止。

上图的执行顺序:

1.左下移动5节点没有子节点,优先执行5

2.遍历5的同级别行源6,执行6

3.执行4

4.遍历同级节点7,执行其子节点8

5.执行3

6.遍历同级节点,执行其最左下节点,执行10

7.执行11

8.执行9

9.执行2

10.执行1

11.执行0


二、Explain Plan For SQL

SQL> explain plan for select * from emp;

Explained.

显示执行计划

SQL> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id  | Operation	  | Name | Rows  | Bytes | Cost (%CPU)| Time	 |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |	 |    14 |   532 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMP  |    14 |   532 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

8 rows selected.

这种方法并没有真正的执行sql语句,查看执行计划也比较麻烦,基本上不使用。


三、SQL_TRACE

   SQL_TRACE是Oracle的一个非常强大的工具。打开SQL_TRACE就可以逐步捕获任何一个会话的数据库活动,或者捕获整个数据库的活动,并将数据库活动记录成跟踪文件。每次使用完之后需要关闭跟踪,否则会降低系统的性能。

  • 跟踪整个数据库实例。

  只需要简单的修改参数文件(pfile/spfile)参数 SQL_TRACE = TRUE ,在全局启用SQL_TRACE会导致所有进程的活动被跟踪,包括后台进程及所有用户进程,这样也会数据库导致性能下降比较明显。

  • 会话级跟踪。

   SQL_TRACE的通常使用方式是仅跟踪一个会话。被跟踪的会话可以是您自己的,也可以是其它用户的会话。如果是自己的会话,只需要在SQL*PLUS中运行一下命令即可:

 SQL> alter session set sql_trace = true;

  类似的如果取消对会话的跟踪,运行一下命令:

 SQL> alter session set sql_trace = false;

   如果需要跟踪一个特定的会话,首先需要获取会话的SID和Serial#,这些信息可以在视图V$SESSION中获得,一旦知道了这两个参数,就可以运行一下命令:

SQL> execute SYS.dbms_system.set_sql_trace_in_session(13,9,true);

同样也可以使用这个过程关闭会话跟踪:

SQL> execute SYS.dbms_system.set_sql_trace_in_session(13,9,false);

跟踪文件的位置:
  一旦为会话激活了SQL_TRACE,ORACLE就会在udump管理区创建跟踪文件,文件的目标位置由参数user_dump_dest来确定。每个操作都不会覆盖原来的文件,新的跟踪记录将会被追加到文件末尾。通常情况下,可以根据文件的修改时间判断目录下哪个文件是最新的文件。

SQL> show parameter user_dump_dest

NAME				     TYPE			       VALUE
------------------------------------ --------------------------------- ------------------------------
user_dump_dest			     string			       /u01/app/oracle/diag/rdbms/11g
								       dg1/dgtst/trace
SQL>

也可以通过以下SQL来确定文件名:

SQL> 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;    
TRACE_FILE_NAME
-----------------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/11gdg1/dgtst/trace/dgtst_ora_11347.trc

计时信息:
  为了最大限度的利用跟踪文件,应该打开计时标志,通过参数TIMED_STATISTICTS=TRUE进行设置,这样可以对每个SQL语句的执行时间等进行记录,这个功能对系统性能的负担很小。
打开会话的计时信息:

SQL> alter session set timed_statistics = true ;

打开数据库系统的计时信息

SQL> alter system set timed_statistics = true ;

我们来做一个实验:

SQL> alter session set sql_trace=true;
ERROR:
ORA-01031: insufficient privileges
SQL> conn / as sysdba
Connected.
SQL> grant alter session to scott;

Grant succeeded.

执行一个查询

SQL>  alter session set sql_trace=true;

Session altered.

SQL> select * from emp,dept where emp.deptno=dept.deptno;

获取trace_file_name

TRACE_FILE_NAME
----------------------------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/11gdg1/dgtst/trace/dgtst_ora_11450.trc

查看trace file

11gdg1-> cat /u01/app/oracle/diag/rdbms/11gdg1/dgtst/trace/dgtst_ora_11450.trc
Trace file /u01/app/oracle/diag/rdbms/11gdg1/dgtst/trace/dgtst_ora_11450.trc
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
ORACLE_HOME = /u01/app/oracle/product/11.2.0/db_1
System name:	Linux
Node name:	11gdg1.localdomain.com
Release:	2.6.39-400.17.1.el6uek.x86_64
Version:	#1 SMP Fri Feb 22 18:16:18 PST 2013
Machine:	x86_64
VM name:	VMWare Version: 6
Instance name: dgtst
Redo thread mounted by this instance: 1
Oracle process number: 23
Unix process pid: 11450, p_w_picpath: oracle@11gdg1.localdomain.com (TNS V1-V3)


*** 2015-07-13 09:38:29.695
*** SESSION ID:(42.57) 2015-07-13 09:38:29.695
*** CLIENT ID:() 2015-07-13 09:38:29.695
*** SERVICE NAME:(SYS$USERS) 2015-07-13 09:38:29.695
*** MODULE NAME:(SQL*Plus) 2015-07-13 09:38:29.695
*** ACTION NAME:() 2015-07-13 09:38:29.695
 
=====================
PARSING IN CURSOR #139672104506696 len=32 dep=0 uid=83 oct=42 lid=83 tim=1436751509693664 hv=1569151342 ad='7f07f227fe10' sqlid='4tk6t8tfsfqbf'
alter session set sql_trace=true
END OF STMT
EXEC #139672104506696:c=0,e=601,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=1436751509693625

*** 2015-07-13 09:38:47.624
CLOSE #139672104506696:c=0,e=17,dep=0,type=0,tim=1436751527624224
=====================
PARSING IN CURSOR #139672104506696 len=51 dep=0 uid=83 oct=3 lid=83 tim=1436751527625170 hv=4289413451 ad='8bd40480' sqlid='arvwqrbzuqhab'
select * from emp,dept where emp.deptno=dept.deptno
END OF STMT
PARSE #139672104506696:c=0,e=814,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=844388907,tim=1436751527625164
EXEC #139672104506696:c=0,e=315,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=844388907,tim=1436751527625549
FETCH #139672104506696:c=1000,e=1189,p=0,cr=8,cu=0,mis=0,r=1,dep=0,og=1,plh=844388907,tim=1436751527641018
FETCH #139672104506696:c=0,e=52,p=0,cr=2,cu=0,mis=0,r=13,dep=0,og=1,plh=844388907,tim=1436751527641868
STAT #139672104506696 id=1 cnt=14 pid=0 pos=1 obj=0 op='MERGE JOIN  (cr=10 pr=0 pw=0 time=1393 us cost=6 size=812 card=14)'
STAT #139672104506696 id=2 cnt=4 pid=1 pos=1 obj=75333 op='TABLE ACCESS BY INDEX ROWID DEPT (cr=4 pr=0 pw=0 time=605 us cost=2 size=80 card=4)'
STAT #139672104506696 id=3 cnt=4 pid=2 pos=1 obj=75334 op='INDEX FULL SCAN PK_DEPT (cr=2 pr=0 pw=0 time=286 us cost=1 size=0 card=4)'
STAT #139672104506696 id=4 cnt=14 pid=1 pos=2 obj=0 op='SORT JOIN (cr=6 pr=0 pw=0 time=818 us cost=4 size=532 card=14)'
STAT #139672104506696 id=5 cnt=14 pid=4 pos=1 obj=75335 op='TABLE ACCESS FULL EMP (cr=6 pr=0 pw=0 time=766 us cost=3 size=532 card=14)'

如果你直接用cat命令查看上面的文件的话,根本看不懂。Oracle提供了一个工具TKPROF 

11gdg1-> tkprof /u01/app/oracle/diag/rdbms/11gdg1/dgtst/trace/dgtst_ora_11450.trc  trace.sql

TKPROF: Release 11.2.0.3.0 - Development on Mon Jul 13 09:41:05 2015

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
11gdg1-> cat trace.sql 

TKPROF: Release 11.2.0.3.0 - Development on Mon Jul 13 09:41:05 2015

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Trace file: /u01/app/oracle/diag/rdbms/11gdg1/dgtst/trace/dgtst_ora_11450.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
********************************************************************************

SQL ID: 4tk6t8tfsfqbf Plan Hash: 0

alter session set sql_trace=true


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 mode: ALL_ROWS
Parsing user id: 83  
********************************************************************************

SQL ID: arvwqrbzuqhab Plan Hash: 844388907

select * 
from
 emp,dept where emp.deptno=dept.deptno


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0         10          0          14
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0         10          0          14

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 83  
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
        14         14         14  MERGE JOIN  (cr=10 pr=0 pw=0 time=1393 us cost=6 size=812 card=14)
         4          4          4   TABLE ACCESS BY INDEX ROWID DEPT (cr=4 pr=0 pw=0 time=605 us cost=2 size=80 card=4)
         4          4          4    INDEX FULL SCAN PK_DEPT (cr=2 pr=0 pw=0 time=286 us cost=1 size=0 card=4)(object id 75334)
        14         14         14   SORT JOIN (cr=6 pr=0 pw=0 time=818 us cost=4 size=532 card=14)
        14         14         14    TABLE ACCESS FULL EMP (cr=6 pr=0 pw=0 time=766 us cost=3 size=532 card=14)




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

OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      2      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0         10          0          14
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        5      0.00       0.00          0         10          0          14

Misses in library cache during parse: 0
Misses in library cache during execute: 1


OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      0      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        0      0.00       0.00          0          0          0           0

Misses in library cache during parse: 0

    2  user  SQL statements in session.
    0  internal SQL statements in session.
    2  SQL statements in session.
********************************************************************************
Trace file: /u01/app/oracle/diag/rdbms/11gdg1/dgtst/trace/dgtst_ora_11450.trc
Trace file compatibility: 11.1.0.7
Sort options: default

       1  session in tracefile.
       2  user  SQL statements in trace file.
       0  internal SQL statements in trace file.
       2  SQL statements in trace file.
       2  unique SQL statements in trace file.
      44  lines in trace file.
      17  elapsed seconds in trace file.


四、使用DBMS_XPLAY

DBMS_XPLAN提供了5个函数

  • DISPLAY - 格式化和显示plan table中的内容。

  • DISPLAY_AWR - 格式化和显示存储在AWR中的sql语句的执行计划。

  • DISPLAY_CURSOR - 格式化和显示任意shared pool中加载的sql语句的执行计划。

  • DISPLAY_SQL_PLAN_BASELINE - 显示被SQL handle标识的SQL语句的一个或者多个执行计划。

  • DISPLAY_SQLSET - 格式化和显示存储在SQL tuning set中的sql语句的执行计划

1.DISPLAY

SQL> EXPLAIN PLAN FOR
      SELECT * FROM emp e, dept d
         WHERE e.deptno = d.deptno
         AND e.ename='benoit';

Explained.

SQL> SET LINESIZE 130
SQL> SET PAGESIZE 0
SQL> SELECT * FROM table(DBMS_XPLAN.DISPLAY);

Plan hash value: 3625962092

----------------------------------------------------------------------------------------
| Id  | Operation		     | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT	     |	       |     1 |    58 |     4	 (0)| 00:00:01 |
|   1 |  NESTED LOOPS		     |	       |       |       |	    |	       |
|   2 |   NESTED LOOPS		     |	       |     1 |    58 |     4	 (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL	     | EMP     |     1 |    38 |     3	 (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN	     | PK_DEPT |     1 |       |     0	 (0)| 00:00:01 |
|   5 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1	 (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("E"."ENAME"='benoit')
   4 - access("E"."DEPTNO"="D"."DEPTNO")

18 rows selected.

2. DISPLAY_AWR

SQL> SELECT SQL_ID FROM  DBA_HIST_SQLTEXT WHERE ROWNUM<=1;
424h0nf7bhqzd

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('424h0nf7bhqzd'));

查看历史查询中包含TOTO的语句的执行计划

SELECT tf.*
  FROM DBA_HIST_SQLTEXT ht,
       TABLE (DBMS_XPLAN.DISPLAY_AWR (ht.sql_id,
                                      NULL,
                                      NULL,
                                      'ALL')) tf
 WHERE ht.sql_text LIKE '%TOTO%';


3.DISPLAY_CURSOR 

SQL> CONN SCOTT/tiger
Connected.
SQL> select * from emp where ename='KING';

     EMPNO ENAME			  JOB				     MGR
---------- ------------------------------ --------------------------- ----------
HIREDATE		   SAL	     COMM     DEPTNO
------------------- ---------- ---------- ----------
      7839 KING 			  PRESIDENT
1981/11/17 00:00:00	  5000			  10


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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID	7y29yzz506y9t, child number 0
-------------------------------------
select * from emp where ename='KING'

Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id  | Operation	  | Name | Rows  | Bytes | Cost (%CPU)| Time	 |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |	 |	 |	 |     3 (100)| 	 |
|*  1 |  TABLE ACCESS FULL| EMP  |     1 |    38 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("ENAME"='KING')


18 rows selected.

DISPLAY_CURSOR还有很多丰富的用法,我们看看官方文档是怎么描述的。

wKiom1XUT2nTn03ZAARQRIh0xU0129.jpg

       wKioL1XUUinTq8ldAANs_soHv9o918.jpg

      wKiom1XUUDPhRxRCAAF_2wmVw9M602.jpg

查看一个具体sql_id的执行计划

SQL> SELECT SQL_ID FROM V$SQLAREA WHERE ROWNUM<=1;

SQL_ID
---------------------------------------
4dy1xm4nxc0gf

SQL>  select * from table(dbms_xplan.display_cursor('4dy1xm4nxc0gf',NULL,'ALL ALLSTATS'));

4.DISPLAY_SQL_PLAN_BASELINE

SET LINESIZE 150
SET PAGESIZE 2000
SELECT t.*
  FROM (SELECT DISTINCT sql_handle
          FROM dba_sql_plan_baselines
         WHERE sql_text LIKE '%DEPT%') pb,
       TABLE (
          DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE (pb.sql_handle, NULL, 'BASIC')) t;