执行计划 描述数据库引擎执行SQL语句时实施的操作

一、获取执行计划:
执行EXPLAIN PLAN语句,然后查询其输出所写入的表
查询动态性能视图来显示缓存在库缓存中的执行计划
使用实时监控来获取关于正在执行或者刚刚执行完毕的SQL语句的信息
查询自动工作负载存储库(AWR)或statspack表,显示存储在存储库中的执行计划
激活跟踪功能提供执行计划

1、EXPLAIN PLAN语句

EXPLAIN PLAN的目标
接受一个SQL语句作为输入,然后提供它的执行计划和相关信息,并在计划表中作为输出显示
EXPLAIN PLAN语句的语法:
EXPLAIN PLAN
[SET STATEMENT_ID = id]
[ INTO [ schema. ] table_name [ @ dblink ] ]
FOR sql_statement
sql_statement指定应该为哪一条SQL语句提供执行计划
id指定一个名称,用于区分存储在计划表中的多个执行计划
table_name指定将关于执行计划的信息插入到计划表的名称,这个参数是可选的,默认值是plan_table。这里也可以使用通常的语法指定一个模式名以及数据库链接名:schema.table@dblink

1.1 计划表

计划表存放的是EXPLAIN PLAN语句输出的内容。
默认计划表归sys用户所有。(oracle 10g开始)一个名为plan_table的公共同义词将这张表暴露给所有的用户
默认的计划表示一张会将数据存储直到会话结束的全局临时表。通过这种方式,几个并发的用户可以同时使用它而不互相干扰
如果需要一张私有的计划表,可以通过$ORACLE_HOME/rdms/admin目录下的utlxplan.sql脚本手工创建
查询计划表
EXPLAN PLAN FOR <sql_statement>
SELECT * FROM table(dbms_xplan.display);

默认计划表是一个全局临时表,所以你无法看到其他会话插入的执行计划,你的执行计划也会随着自己会话的结束而自动消失

1.2 绑定变量陷阱
常见的错误:指定了一个有别于要分析语句的SQL语句
eg:
查询PL/SQL中的查询语句使用的执行计划
CREATE OR REPLACE p (p_value IN NUMBER) IS
BEGIN
  FOR i IN ( SELECT * FROM emp WHERE empno = p_value )
  LOOP
    NULL;
  END LOOP;
END
常用的方法是使用字面值替换PL/SQL变量来查询执行计划,即
EXPLAIN PLAN FOR SELECT * FROM emp WHERE empno = 7788,这种使用字面值替换绑定变量的做法可能会对查询优化器做出的决定有影响
正确的是使用相同的SQL语句: EXPLAIN PLAN FOR SELECT * FROM emp WHERE empno = :B1

EXPLAIN PLAN FOR SELECT * FROM emp WHERE empno = :B1,该方法存在两个问题:
默认情况下,绑定变量会被声明为VARCHAR2类型,这样的话数据库引擎会自动添加一个隐式转换,会造成执行计划的改变。通常,检查是否处理了数据类型是很好的做法
在EXPLAIN PLAN语句中使用绑定变量时不会使用绑定变量扫视技术,该问题没有解决方案,所以不能保证通过EXPLAN PLAN语句生成的执行计划就是运行时选择的执行计划,即一旦涉及绑定变量,通过EXPLAIN PLAN语句生成的输出是靠不住的

2、动态性能视图

2.1 四个性能视图会显示关于出现在库缓存中的游标信息
v$sql_plan 提供与计划表基本上相同的信息。与计划表的唯一显著区别是它有几个用于标识与库缓存中的执行计划关联的游标的列
v$sql_plan_statistics为v$sql_plan视图中的每一个操作提供执行统计,例如消耗的时间和产生的行数。v$sql_plan只显示查询优化器在解析阶段做出的估算。由于执行统计信息的采集可能会引发不可忽略的负载,默认情况下不会采集它们
v$sql_workarea提供关于执行游标所需的内存工作区的信息。它给出运行时内存以及估算的高效执行操作所需要的内存总量信息
v$sql_plan_statistics_all将v$sql_plan、v$sql_plan_statistics以及v$sql_workarea视图提供的信息通过一个单独的视图展现出来。通过他可以避免手工连接多个视图

2.2 标识子游标
获取与当前连接到实例的会话有关的SQL的信息,可以在v$session中查找
当前执行的SQL语句是通过sql_id(或者sql_address)和sql_child_number来标识的
最近执行的SQL语句是通过pre_sql_id(或者pre_sql_address)和pre_sql_child_number来标识的
select status, sql_id, sql_child_number from v$session where <conditions>;
当知道所需要更多信息的SQL语句的文本,可以在v$sql视图中查找
与游标有关联的文本可以在sql_text和sql_fulltext列中找到
两个列的区别是sql_text只能通过一个VARCHAR2(1000)的值显示部分的文本,而sql_fulltext列通过CLOB类型的值显示全部文本
select sql_id, child_number, sql_text from v$sql where sql_fulltext like '%SQL文本%'

2.3 查询动态性能视图
要获得执行计划,可以直接在v$sql_plan和v$sql_plan_statistics_all视图上执行查询
更简单更好的方式:使用dbms_xplan包的display_cursor函数
SELECT * FROM table(dbms_xplan.display_cursor('sql_id', 0))
其与视图查询唯一的区别是将标识要显示的子游标的两个参数传递给display_cursor函数

3、自动工作负载存储库(AWR)和Statspack

AWR和Statspack能够收集执行计划
存储在AWR中的执行计划可以通过dba_hist_sql_plan视图进行访问(12.1版本后也可以使用cdb_hist_sql_plan视图进行访问)
dbms_xplan包提供了display_awr函数,可用于查询执行计划
SELECT * FROM table(dbms_xplan.display_awr('SQL_ID’))
当使用一个大于或者等于6的级别捕获快照时,Statspack将执行计划存储在stats$sql_plan存储库中。dbms_xplan包中没有提供具体的函数来查询存储库的表,但是可以利用display函数来显示其中包含的执行计划
对于AWR和Statspack,oracle数据库都提供了实用的脚本,为具体的SQL语句高亮显示一段时间内的执行计划的改变和资源消耗的变化,它们分别是awrsqrpt.sql和sprepsql.sql,位于$ORACLE_HOME/rdbms/admin目录下