欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Oracle中使用DBMS_XPLAN处理执行计划详解

程序员文章站 2023-11-17 19:48:10
dbms_xplan是oracle提供的一个用于查看sql计划,包括执行计划和解释计划的包;在以前查看sql执行计划的时候,我都是使用set autotrace命令,不过现...

dbms_xplan是oracle提供的一个用于查看sql计划,包括执行计划和解释计划的包;在以前查看sql执行计划的时候,我都是使用set autotrace命令,不过现在看来,dbms_xplan包给出了更加简化的获取和显示计划的方式。

这5个函数分别对应不同的显示计划的方式,dbms_xplan包不仅可以获取解释计划,它还可以用来输出存储在awr,sql调试集,缓存的sql游标,以及sql基线中的语句计划,实现如上的功能,通常会用到一下5个方法:

1.display
2.display_awr
3.display_cursor
4.display_plan
5.display_sql_plan_baseline
6.display_sqlset

下面将重点讨论关于dbms_xplan包在解释计划和执行计划上的应用。

来看一个经常使用的查看某条语句的解释计划示例:

复制代码 代码如下:

sql> explain plan for select * from scott.emp;

explained.

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

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.

-- 对应autotrace实现
sql> set autotrace traceonly explain


上例中使用了dbms_xplan.display方法来显示plan_table中保存的解释计划,如果想要显示执行计划,就需要使用到dmbs_xplan.display_cursor方法了,dmbs_xplan.display_cursor调用签名:

复制代码 代码如下:

dbms_xplan.display_cursor(
   sql_id        in  varchar2  default  null,
   child_number  in  number    default  null,
   format        in  varchar2  default  'typical');

sql_id表示存储在cursor cache中的sql语句的id,child_number用于指示缓存sql语句计划的子id,format参数用于控制包含在输出中的信息类型,官档的参数如下:

1.basic: 显示最少的信息,只包括操作类型,id名称和选项。
2.typical: 默认值,显示相关信息以及某些附加的显示选项,如分区和并发使用等。
3.serial: 与typical类型相似,区别是它不包括并发的信息,即使是并行执行的计划。
4.all: 显示最多的信息,包含了typical的全部以及更多的附加信息,如别名和远程调用等。

除了以上的基本的四种输出格式外,format还有一些附加的选项可用于定制化输出行为,使用中可以通过逗号和空格分隔来声明多个关键字,同时可以使用”+”和”-”符号来包含或排除相应的显示元素,这些附加的选项在官档中也有记载:

1.rows – 显示被优化器估算的记录的行号
2.bytes – 显示优化器估算的字节数
3.cost – 显示优化器计算的成本信息
4.partition – 显示分区的分割信息
5.parallel – 显示并行执行信息
6.predicate – 显示谓语
7.projection – 显示列投影部分(每一行的那些列被传递给其父列已经这些列的大小)
8.alias – 显示查询块名称已经对象别名
9.remote – 显示分布式查询信息
10.note – 显示注释
11.iostats – 显示游标执行的io统计信息
12.memstats – 为内存密集运算如散列联结,排序,或一些类型的位图运算显示内存管理统计信息
13.allstats – 与'iostats memstats'等价
14.last – 显示最后执行的执行计划统计信息,默认显示为all类型,并且可以累积。

以上的参数同样适用于解释计划的display方法。

示例部分:

一、使用display_cursor方法查看最近一条语句的执行计划

复制代码 代码如下:

sql> select /*+ gather_plan_statistics */ count(*) from scott.emp;

  count(*)
----------
        14

sql> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

plan_table_output
-------------------------------------------------------------------------------------------------------
sql_id  f9qyz8s3c2c02, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from scott.emp

plan hash value: 2937609675

-------------------------------------------------------------------------------------
| id  | operation        | name   | starts | e-rows | a-rows |   a-time   | buffers |
-------------------------------------------------------------------------------------
|   0 | select statement |        |      1 |        |      1 |00:00:00.01 |       1 |
|   1 |  sort aggregate  |        |      1 |      1 |      1 |00:00:00.01 |       1 |
|   2 |   index full scan| pk_emp |      1 |     14 |     14 |00:00:00.01 |       1 |
-------------------------------------------------------------------------------------

14 rows selected.

使用dbms_xplan.display_cursor(null,null,'allstats last')时,将sql_id和child_number设置成null,表示获取上一条执行语句的执行计划;注意上面的例子中一定要指定gather_plan_statistics提示或者手动设置数据库statistics_level参数为all来使得其抓取行数据源的执行统计信息,这些信息包括行数,一直读取次数,物理读次数,物理写次数以及运算在一行数据上耗费的运行时间,如果没有指定该提示,就不会有a-rows,a-time,buffers这三列信息。

二、获取某条指定语句的执行计划

复制代码 代码如下:

sql> select /*+ gather_plan_statistics */ count(*) from hr.employees where department_id in (90, 100);

  count(*)
----------
         9

-- 通过v$sql视图查询到sql语句的sql_id和child_number
sql> select sql_id,child_number,sql_text from v$sql
  2  where sql_text like '%select /*+ gather_plan_statistics */ count(*)%';

sql_id        child_number sql_text
------------- ------------ ----------------------------------------------------------------------------------------------------
5qxmkvh40yw0p            0 select /*+ gather_plan_statistics */ count(*) from hr.employees where department_id in (90, 100)
bqjrnskvpv51n            0 select sql_id,child_number,sql_text from v$sql where sql_text like '%select /*+ gather_plan_statisti
                           cs */ count(*)%'

-- 获取对应的执行计划
sql> select * from table(dbms_xplan.display_cursor('5qxmkvh40yw0p',0,'allstats last'));

plan_table_output
----------------------------------------------------------------------------------------------------
sql_id  5qxmkvh40yw0p, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from hr.employees where
department_id in (90, 100)

plan hash value: 4167091351

--------------------------------------------------------------------------------------------------
| id  | operation          | name              | starts | e-rows | a-rows |   a-time   | buffers |
--------------------------------------------------------------------------------------------------
|   0 | select statement   |                   |      1 |        |      1 |00:00:00.01 |       2 |
|   1 |  sort aggregate    |                   |      1 |      1 |      1 |00:00:00.01 |       2 |
|   2 |   inlist iterator  |                   |      1 |        |      9 |00:00:00.01 |       2 |
|*  3 |    index range scan| emp_department_ix |      2 |      9 |      9 |00:00:00.01 |       2 |
--------------------------------------------------------------------------------------------------

predicate information (identified by operation id):
---------------------------------------------------

   3 - access(("department_id"=90 or "department_id"=100))

21 rows selected.

三、通过format参数定制执行计划输出信息

复制代码 代码如下:

-- 使用all来显示解释计划的全部信息
sql> explain plan for
  2  select * from emp e, dept d
  3  where e.deptno = d.deptno
  4  and e.ename = 'jones' ;

explained.

sql> select * from table(dbms_xplan.display(format=>'all'));

plan_table_output
----------------------------------------------------------------------------------------------------
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 |

query block name / object alias (identified by operation id):
-------------------------------------------------------------

   1 - 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 - filter("e"."ename"='jones')
   4 - access("e"."deptno"="d"."deptno")

column projection information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) "e"."empno"[number,22], "e"."ename"[varchar2,10],
       "e"."job"[varchar2,9], "e"."mgr"[number,22], "e"."hiredate"[date,7],
       "e"."sal"[number,22], "e"."comm"[number,22], "e"."deptno"[number,22],
       "d"."deptno"[number,22], "d"."dname"[varchar2,14], "d"."loc"[varchar2,13]
   2 - (#keys=0) "e"."empno"[number,22], "e"."ename"[varchar2,10],
       "e"."job"[varchar2,9], "e"."mgr"[number,22], "e"."hiredate"[date,7],
       "e"."sal"[number,22], "e"."comm"[number,22], "e"."deptno"[number,22],
       "d".rowid[rowid,10], "d"."deptno"[number,22]
   3 - "e"."empno"[number,22], "e"."ename"[varchar2,10], "e"."job"[varchar2,9],
       "e"."mgr"[number,22], "e"."hiredate"[date,7], "e"."sal"[number,22],
       "e"."comm"[number,22], "e"."deptno"[number,22]
   4 - "d".rowid[rowid,10], "d"."deptno"[number,22]
   5 - "d"."dname"[varchar2,14], "d"."loc"[varchar2,13]

43 rows selected.

-- 去除执行计划上的字节数和成本统计信息
sql> select empno, ename from emp e, dept d
  2  where e.deptno = d.deptno
  3  and e.ename = 'jones' ;

     empno ename
---------- ----------
      7566 jones

sql> select * from table(dbms_xplan.display_cursor(null,null,format=>'allstats last -cost -bytes'));

plan_table_output
----------------------------------------------------------------------------------------------------
sql_id  3mypf7d6npa97, child number 1
-------------------------------------
select empno, ename from emp e, dept d where e.deptno = d.deptno and
e.ename = 'jones'

plan hash value: 3956160932

------------------------------------------------------------------------------------
| id  | operation         | name | starts | e-rows | a-rows |   a-time   | buffers |
------------------------------------------------------------------------------------
|   0 | select statement  |      |      1 |        |      1 |00:00:00.01 |       8 |
|*  1 |  table access full| emp  |      1 |      1 |      1 |00:00:00.01 |       8 |
------------------------------------------------------------------------------------

predicate information (identified by operation id):
---------------------------------------------------

   1 - filter(("e"."ename"='jones' and "e"."deptno" is not null))

19 rows selected.

-- 另一种选项,窥视绑定变量的值,非常方便!!
sql> variable v_empno number
sql> exec :v_empno := 7566 ;

pl/sql procedure successfully completed.

sql> select * from emp where empno = :v_empno ;

     empno ename      job              mgr hiredate         sal       comm     deptno
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7566 jones      manager         7839 02-apr-81       2975                    20

sql> select * from table(dbms_xplan.display_cursor(null,null,format=>'+peeked_binds'));

plan_table_output
----------------------------------------------------------------------------------------------------
sql_id  9q17w9umt58m7, child number 0
-------------------------------------
select * from emp where empno = :v_empno

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 |    38 |     1   (0)| 00:00:01 |
|*  2 |   index unique scan         | pk_emp |     1 |       |     0   (0)|          |
--------------------------------------------------------------------------------------

peeked binds (identified by position):
--------------------------------------

   1 - :v_empno (number): 7566

predicate information (identified by operation id):
---------------------------------------------------

plan_table_output
----------------------------------------------------------------------------------------------------
   2 - access("empno"=:v_empno)

24 rows selected.

-- 并行查询信息筛选
sql> select /*+ parallel(d, 4) parallel (e, 4) */
  2  d.dname, avg(e.sal), max(e.sal)
  3  from dept d, emp e
  4  where d.deptno = e.deptno
  5  group by d.dname
  6  order by max(e.sal), avg(e.sal) desc;

dname          avg(e.sal) max(e.sal)
-------------- ---------- ----------
sales          1566.66667       2850
research             2175       3000
accounting     2916.66667       5000

sql> select * from table(dbms_xplan.display_cursor(null,null,'typical -bytes -cost'));

plan_table_output
----------------------------------------------------------------------------------------------------
sql_id  gahr597f78j0d, child number 0
-------------------------------------
select /*+ parallel(d, 4) parallel (e, 4) */ d.dname, avg(e.sal),
max(e.sal) from dept d, emp e where d.deptno = e.deptno group by
d.dname order by max(e.sal), avg(e.sal) desc

plan hash value: 3078011448

--------------------------------------------------------------------------------------------------
| id  | operation                     | name     | rows  | time     |    tq  |in-out| pq distrib |
--------------------------------------------------------------------------------------------------

plan_table_output
----------------------------------------------------------------------------------------------------
|   0 | select statement              |          |       |          |        |      |            |
|   1 |  px coordinator               |          |       |          |        |      |            |
|   2 |   px send qc (order)          | :tq10004 |     4 | 00:00:01 |  q1,04 | p->s | qc (order) |
|   3 |    sort order by              |          |     4 | 00:00:01 |  q1,04 | pcwp |            |
|   4 |     px receive                |          |     4 | 00:00:01 |  q1,04 | pcwp |            |
|   5 |      px send range            | :tq10003 |     4 | 00:00:01 |  q1,03 | p->p | range      |
|   6 |       hash group by           |          |     4 | 00:00:01 |  q1,03 | pcwp |            |
|   7 |        px receive             |          |    14 | 00:00:01 |  q1,03 | pcwp |            |
|   8 |         px send hash          | :tq10002 |    14 | 00:00:01 |  q1,02 | p->p | hash       |
|*  9 |          hash join buffered   |          |    14 | 00:00:01 |  q1,02 | pcwp |            |
|  10 |           px receive          |          |     4 | 00:00:01 |  q1,02 | pcwp |            |
|  11 |            px send hash       | :tq10000 |     4 | 00:00:01 |  q1,00 | p->p | hash       |
|  12 |             px block iterator |          |     4 | 00:00:01 |  q1,00 | pcwc |            |
|* 13 |              table access full| dept     |     4 | 00:00:01 |  q1,00 | pcwp |            |
|  14 |           px receive          |          |    14 | 00:00:01 |  q1,02 | pcwp |            |
|  15 |            px send hash       | :tq10001 |    14 | 00:00:01 |  q1,01 | p->p | hash       |
|  16 |             px block iterator |          |    14 | 00:00:01 |  q1,01 | pcwc |            |
|* 17 |              table access full| emp      |    14 | 00:00:01 |  q1,01 | pcwp |            |
--------------------------------------------------------------------------------------------------

predicate information (identified by operation id):
---------------------------------------------------

   9 - access("d"."deptno"="e"."deptno")
  13 - access(:z>=:z and :z<=:z)   17 - access(:z>=:z and :z<=:z)

38 rows selected.