Oracle获取执行计划之DBMS_XPLAN 技术详解1

发布于:2025-06-25 ⋅ 阅读:(23) ⋅ 点赞:(0)

在 Oracle 数据库的管理与优化工作中,深入了解 SQL 语句的执行计划是至关重要的一环。DBMS_XPLAN 包作为 Oracle 提供的强大工具,能够帮助数据库管理员(DBAs)和开发人员清晰地查看和分析 SQL 语句的执行计划,从而实现对数据库性能的有效优化。本文将全面深入地介绍 DBMS_XPLAN 包的相关知识。

一、DBMS_XPLAN 包概述

DBMS_XPLAN 包是 Oracle 内置的实用工具,主要用于展示 SQL 语句的执行计划。当我们向 Oracle 数据库发出一条 SQL 查询时,数据库会确定一种最有效的方式来执行该查询,这个执行方式的具体描述就是执行计划。执行计划涵盖了 Oracle 为检索或修改所需数据而执行的精确操作,包括表的连接方式、数据的访问路径以及索引的使用情况等。

传统的explain plan语句常用于生成执行计划,但它仅仅是对执行计划的预测,并不一定能准确反映 SQL 语句在实际运行时的行为。而 DBMS_XPLAN 包则更具优势,它不仅可以展示预测的执行计划,还能根据查询类型呈现实际运行时的性能表现,为我们深入分析 SQL 语句的执行过程提供了更可靠的依据。

 二、DBMS_XPLAN 包的使用前提

要使用 DBMS_XPLAN 包,需要满足以下条件:

  1. 权限要求:用户需要具备查询计划表(plan_table)或v$sql_plan视图的权限。其中,plan_table是用于存储explain plan命令输出结果的临时表;v$sql_plan视图则包含了已执行查询的实际执行计划。
  2. SQL 语句的可用性:如果要获取实时的执行计划,那么所分析的查询必须仍然存在于共享 SQL 区域中;如果是进行历史分析,则需要确保该查询的执行计划之前已被捕获并存储。

当执行explain plan后,Oracle 会自动向plan_table填充相关内容,此时 DBMS_XPLAN 包就能对这些内容进行格式化处理,使其更易于阅读和理解。

三、DBMS_XPLAN 包的核心函数

DBMS_XPLAN 包包含多个关键函数,每个函数都针对特定的使用场景进行设计,以下是对这些函数的详细介绍:

3.1 display函数

(一)display函数参数说明

display函数主要用于展示存储在计划表(plan_table)中的执行计划。其调用格式如下:

select * from table(dbms_xplan.display(table_name, statement_id, format, filter_preds));
  • table_name:用于指定计划表的名称,默认值为plan_table,如果填入null,则表示采用默认的计划表。 
  • statement_id:用于指定 SQL 语句的名称,默认值为null,在这种情况下,函数将显示最近插入到计划表中的执行计划。 
  • format:该参数用于控制输出内容的格式,常见的取值包括:
  1. basic:只显示最基本的信息,简洁明了。
  2. typical:显示常规的执行计划信息,是较为常用的一种格式。 
  3. all:展示所有相关信息,内容最为全面。 
  4. advanced:提供最全的信息,适合对执行计划进行深入分析的场景。 
  •  filter_preds:用于在查询计划表时添加约束条件,例如statement_id = 'test3' 。默认值为null,表示显示最近插入计划表的执行计划,不添加额外约束。

(二)display 示例

首先,使用explain plan for语句生成执行计划并将其存入plan_table :

explain plan for select * from test1; 

然后,通过dbms_xplan.display函数来展示执行计划:

select * from table(dbms_xplan.display); 

这种方式和explain plan展示一样,这里就不做具体示例展示。

下面补充一个非常实用的功能,就是当一个SQL带有绑定变量时,explain plan for仍然可以解析。

SQL> explain plan for select object_id,object_name,owner from test1 where rownum<:1;

Explained.

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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1430905904

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       | 91074 |  8538K|   336   (1)| 00:00:05 |
|*  1 |  COUNT STOPKEY     |       |       |       |            |          |
|   2 |   TABLE ACCESS FULL| TEST1 | 91074 |  8538K|   336   (1)| 00:00:05 |
----------------------------------------------------------------------------

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

   1 - filter(ROWNUM<TO_NUMBER(:1))

Note
-----
   - dynamic sampling used for this statement (level=2)

18 rows selected.

3.2 display_cursor函数

(一)display_cursor函数参数说明

display_cursor函数用于显示存储在库缓存(v$sql_plan视图 )中的执行计划,由于它是直接从共享池的library cache内存中直接获取,所以获取的执行计划是真实的,其格式为:

select * from table(dbms_xplan.display_cursor(sql_id, cursor_child_no, format));
  • sql_id:指定要返回执行计划的SQL语句的父游标,默认值为null。当取值为null时,函数将返回当前会话最后被执行的SQL语句的执行计划。
  • cursor_child_no:用于指定父游标下子游标的序号,默认值为0。若将其设定为null,则表示返回所有子游标的执行计划。
  •  format:与display函数中的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.     PEEKED_BINDS:打印解析时使用的绑定变量
  14.     ALLSTATS:与IOSTATS MEMSTATS等价。 
  15.     LAST:显示最后执行的执行计划统计信息,默认显示为ALL类型,并且可以累积。

(二)display_cursor示例

  • 展示最近的执行计划(不带绑定变量)

dbms_xplan.display_cursor(null, null, 'ALLSTATS LAST')

SQL> set autot off
SQL> select object_id,object_name,owner from test1 where rownum<10;

 OBJECT_ID OBJECT_NAME          OWNER
---------- -------------------- ------------------------------
        20 ICOL$                SYS
        46 I_USER1              SYS
        28 CON$                 SYS
        15 UNDO$                SYS
        29 C_COBJ#              SYS
         3 I_OBJ#               SYS
        25 PROXY_ROLE_DATA$     SYS
        41 I_IND1               SYS
        54 I_CDEF2              SYS

9 rows selected.

SQL> select * from table(dbms_xplan.display_cursor(null, null, 'ALLSTATS LAST')); 

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------
SQL_ID  d6tfa5t1a8m7w, child number 0
-------------------------------------
select object_id,object_name,owner from test1 where rownum<10

Plan hash value: 1430905904

---------------------------------------------
| Id  | Operation          | Name  | E-Rows |
---------------------------------------------
|   0 | SELECT STATEMENT   |       |        |
|*  1 |  COUNT STOPKEY     |       |        |
|   2 |   TABLE ACCESS FULL| TEST1 |  91074 |
---------------------------------------------

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

   1 - filter(ROWNUM<10)

Note
-----
   - dynamic sampling used for this statement (level=2)
   - Warning: basic plan statistics not available. These are only collected when:
       * hint 'gather_plan_statistics' is used for the statement or
       * parameter 'statistics_level' is set to 'ALL', at session or system level


26 rows selected.

这里由于没有参考统计信息,报一个警告。另外还有其它常用的参数,例如ADVANCED,ALL请读者自行尝试。

  • 展示最近的执行计划(带绑定变量)
-- 1. 创建测试表并插入示例数据
CREATE TABLE employees (
    employee_id NUMBER PRIMARY KEY,
    first_name VARCHAR2(50),
    last_name VARCHAR2(50),
    department_id NUMBER,
    salary NUMBER,
    hire_date DATE
);

INSERT INTO employees VALUES (1, 'John', 'Doe', 10, 6000, SYSDATE);
INSERT INTO employees VALUES (2, 'Jane', 'Smith', 20, 7500, SYSDATE-100);
INSERT INTO employees VALUES (3, 'Mike', 'Johnson', 20, 5500, SYSDATE-200);
INSERT INTO employees VALUES (4, 'Sarah', 'Williams', 30, 9000, SYSDATE-150);
COMMIT;

-- 2. 创建索引以支持查询
CREATE INDEX idx_dept_sal ON employees (department_id, salary);

-- 3. 执行带有绑定变量的SQL(使用绑定变量而非硬编码值)
VARIABLE dept_id NUMBER;
VARIABLE min_salary NUMBER;
EXEC :dept_id := 20;
EXEC :min_salary := 5000;

SELECT /*+ MONITOR */ * 
FROM employees 
WHERE department_id = :dept_id 
  AND salary > :min_salary;

-- 4. 立即查看执行计划(包含绑定变量值)
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST PEEKED_BINDS'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  gd7vts27rnvua, child number 0
-------------------------------------
SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id
AND salary > :min_salary

Plan hash value: 1445457117

--------------------------------------------------------------------------------
| Id  | Operation         | Name      | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |        |       |     2 (100)|          |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |      2 |   204 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------

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

   1 - SEL$1 / EMPLOYEES@SEL$1

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
      DB_VERSION('11.2.0.4')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "EMPLOYEES"@"SEL$1")
      END_OUTLINE_DATA
  */

Peeked Binds (identified by position):
--------------------------------------

   1 - (NUMBER): 20
   2 - (NUMBER): 5000

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

   1 - filter(("DEPARTMENT_ID"=:DEPT_ID AND "SALARY">:MIN_SALARY))

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "EMPLOYEES"."EMPLOYEE_ID"[NUMBER,22],
       "EMPLOYEES"."FIRST_NAME"[VARCHAR2,50],
       "EMPLOYEES"."LAST_NAME"[VARCHAR2,50], "DEPARTMENT_ID"[NUMBER,22],
       "SALARY"[NUMBER,22], "EMPLOYEES"."HIRE_DATE"[DATE,7]

Note
-----
   - dynamic sampling used for this statement (level=2)
   - Warning: basic plan statistics not available. These are only collected when
:

       * hint 'gather_plan_statistics' is used for the statement or
       * parameter 'statistics_level' is set to 'ALL', at session or system leve
l



59 rows selected.
  • 通过SQLID和游标ID获取执行计划

通过执行select * from table(dbms_xplan.display_cursor('sql_id/hash_value', child_cursor_number, 'advanced'))查看指定 SQL 的执行计划 。

  1. 第一个参数为 SQL ID 或 SQL HASH VALUE 
  2. 第二个是 Child Cursor Number 
  3. 第三个常用advanced以呈现最详细执行计划。
--查看SQLID及游标号
select sql_id,child_number from v$sql where sql_text like 'select object_id,object_name,owner from test1 where%';

SQL_ID        CHILD_NUMBER
------------- ------------
d6tfa5t1a8m7w            0

--查看执行计划
SQL> 
set pages 1000
select * from table(dbms_xplan.display_cursor('d6tfa5t1a8m7w',0,'advanced'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  d6tfa5t1a8m7w, child number 0
-------------------------------------
select object_id,object_name,owner from test1 where rownum<10

Plan hash value: 1430905904

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |       |       |     2 (100)|          |
|*  1 |  COUNT STOPKEY     |       |       |       |            |          |
|   2 |   TABLE ACCESS FULL| TEST1 | 91074 |  8538K|     2   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   1 - SEL$1
   2 - SEL$1 / TEST1@SEL$1

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
      DB_VERSION('11.2.0.4')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "TEST1"@"SEL$1")
      END_OUTLINE_DATA
  */

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

   1 - filter(ROWNUM<10)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "OWNER"[VARCHAR2,30], "OBJECT_NAME"[VARCHAR2,128],
       "OBJECT_ID"[NUMBER,22]
   2 - "OWNER"[VARCHAR2,30], "OBJECT_NAME"[VARCHAR2,128],
       "OBJECT_ID"[NUMBER,22]

Note
-----
   - dynamic sampling used for this statement (level=2)


51 rows selected.

注意:当目标 SQL 执行计划所在的 Child Cursor 未因空间不足等原因被从共享池(Shared Pool)中置换出去(age out )时才能查到执行计划。

3.3 display_awr函数

当 SQL 的执行计划被 age out 出 Shared Pool 后,若该执行计划此前被 Oracle 采集并存储到 AWR(自动工作量存储库,AWR Repository )中,就可以使用该方法查看该 SQL 的所有历史执行计划 。AWR 定期收集、处理和存储数据库性能统计信息以及执行计划等相关数据,即使执行计划不在共享池,只要已被采集到 AWR 中,就能通过特定方法来查看历史执行计划,这为分析 SQL 在不同时间、不同条件下的执行情况提供了途径 。

(一)display_awr函数参数说明

display_awr函数能够从自动工作量存储库(AWR)中存储的历史数据里获取并显示执行计划。这在分析过去某个时段内 SQL 语句的执行情况时非常有用,有助于排查历史性能问题。其语法格式为:

select * from table(dbms_xplan.display_awr(sql_id, plan_hash_value, dbid, format));

其中,sql_id是 SQL 语句的标识;plan_hash_value是执行计划的哈希值;dbid是数据库的唯一标识;format同样用于控制输出格式。

(二)display_awr 示例

  • 查看当前共享池中的执行计划
SQL> col SQL_TEXT for a40
select sql_text, sql_id, version_count,executions from v$sqlarea where sql_text like 'SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id%'; 

SQL_TEXT                                 SQL_ID        VERSION_COUNT EXECUTIONS
---------------------------------------- ------------- ------------- ----------
SELECT /*+ MONITOR */ * FROM employees W gd7vts27rnvua             1          1
HERE department_id = :dept_id   AND sala
ry > :min_salary
  • 采集AWR
exec dbms_workload_repository.create_snapshot();
  • 清空共享池
alter system flush shared_pool;
  • 确认执行计划被置换出共享池
SQL> select sql_text, sql_id, version_count,executions from v$sqlarea where sql_text like 'SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id%'; 

no rows selected

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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID: gd7vts27rnvua, child number: 0 cannot be found
  • 确认执行计划被置换出共享池
SQL> select * from table(dbms_xplan.display_awr('gd7vts27rnvua'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID gd7vts27rnvua
--------------------
SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id
AND salary > :min_salary

Plan hash value: 1445457117

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |       |       |     2 (100)|          |
|   1 |  TABLE ACCESS FULL| EMPLOYEES |     2 |   204 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement (level=2)


18 rows selected.

与DBMS_XPLAN.DISPLAY_CURSOR相比,DBMS_XPLAN.DISPLAY_AWR显示的执行计划存在不足,无法呈现执行步骤对应的谓词条件(包括驱动和过滤查询条件 )。这是由于Oracle将执行计划采样数据从V$SQL_PLAN迁移到AWR Repository基表WRH$_SQL_PLAN时,未保留记录谓词条件的ACCESS_PREDICATES和FILTER_PREDICATES列的值,导致DBMS_XPLAN.DISPLAY_AWR无相关条件可展示,而谓词条件对理解执行计划尤其是复杂计划至关重要。

(四)display_sts函数

display_sts函数主要用于检索存储在 SQL 调试集(STS)中特定 SQL 语句的执行计划。其语法如下:

select * from table(dbms_xplan.display_sts(sqlset_name, sqlset_owner, sql_id, format));

这里,sqlset_name是 SQL 调试集的名称;sqlset_owner是 SQL 调试集的所有者;sql_id是需要查询执行计划的 SQL 语句标识;format用于控制输出信息。

这个使用场景不多,不做过多介绍。

五、DBMS_XPLAN 包的使用总结

DBMS_XPLAN 包在 Oracle 数据库中是查看 SQL 执行计划的得力工具,涵盖了从缓存、AWR、SQL 调试集等多来源的计划展示。通过掌握其各函数的功能、使用方法及适用场景,并留意权限与参数设置等要点,能助力数据库管理员和开发人员精准剖析 SQL 执行情况,高效开展性能优化工作。


网站公告

今日签到

点亮在社区的每一天
去签到