1、什么是执行计划
为了执行sql语句,Oracle在内部必须实现许多步骤,这些步骤可能是从数据库中物理检索数据行,或者用某种方法来准备数据行等,接着Oracle会按照一定的顺序一次执行这些步骤,最后将其执行结果作为目标sql的最终执行结果返回给用户。Oracle用来执行目标sql语句的这些步骤的组合就被称为执行计划。
2、如何查看执行计划
2.1、explain plan命令
如果你问习惯于使用pl/sql developer的同学数据库得到一个sql执行计划,他们很可能不假思索的回答,按F5就可以了。实际上pl/sql developer上按了F5后,调用了explain plan命令,将该命令封装到软件中了。
依次执行下面两条命令
SQL> explain plan for select count(*) from emp;
先使用explain plan命令对目标sql做explain,
SQL> select * from table(dbms_xplan.display);
再查看执行计划。
到底explain plan命令做了什么事情?在10G及以上版本,对目标sql执行explain plan命令后,则Oracle就解析目标sql 所产生的执行计划的具体执行步骤写到plan_table$,随后执行的select * from table(dbms_xplan.display);只是从plan_table$中将这些具体执行步骤以格式化的方式显示出来。plan_table$是一个ON COMMIT PRESERVER ROWS的GLOBAL TEMPORARY TABLE。所以这里Oracle可以做到各个session只能看到自己的执行的sql所产生的执行计划,并且各个session往plan_table$写入执行计划的过程互不干扰。
2.2、DBMS_XPLAN包
使用DBMS_XPLAN包中方法是Oracle数据库中得到目标SQL的执行计划的第二种方法,针对不同的应用场景,你可以选择四种方法中的一种:
2.2.1方法一、select * from table(DBMS_XPLAN.display);
这需要与explain plan命令配合使用,它用于查看使用explain plan命令后得到的执行计划,上面已介绍过。
2.2.2方法二、select * from table(DBMS_XPLAN.display_cursor(null,null,'advanced'));
它用在sqlplus中查看刚刚执行的SQL执行计划,这里针对方法DBMS_XPLAN.display_cursor所传入的第一个和第二个参数的值均为null,第三个参数的值是'advanced',第三个输入参数的值也可以是‘all’,只不过'advanced'后的显示结果比ALL显示更详细些。
2.2.3方法三、select * from table(dbma_xplan.display_cursor('sql_id/hash_value',child_cursor_number,'advanced'));它用于查看指定sql的执行计划,这里针对方法所传入的第一个参数的值是指定sql的sql id或者sql hash value,第二个参数的值是要查看的执行计划所在的child cursor number。只要目标sql所对应的child cursor还在library cache中,我们就可以从v$sql中查到目标sql的child cursor的详细信息,包括sql id、sql hash value、chaild cursor number等,
select sql_text,sql_id,hash_value,child_number from v$sql where sql_text like '%%';查询结果找出对应的sql_id和hash value,本质上sql id 和hash value是一回事,他们是可以互相转换的,所以第一个参数两个值都可以用。只要执行计划所在的child cursor还没有被age out出shared pool,就可以用这种方法获取执行计划。
2.2.4方法四、select * from table(dbms_xplan.display_awr('sql id'));它用于查看指定sql的所有的历史执行计划,使用2、3能够显示目标sql执行计划的前提条件是该sql的执行计划还在shared pool中,而如果该sql的执行计划已经被age out出shared pool,那么只要该sql的执行计划被Oracle采集到awr repository中,我们就可以使用方法4来查看该sql的所有历史执行计划。
这里需要说明的是,到目前为止,用dbms_xplan.display_awr和之前的dbms_xplan.display_cursor显示的执行计划相比,有一个非常不好的地方,就是用dbms_xplan.display_awr显示执行计划中看不到执行步骤对应的谓词条件,这是非常糟糕的。因为谓词条件对于我们理解执行计划,特别是理解复杂执行计划是不可或缺的。这里的根本原因是Oracle在把执行计划的采样数据从v$sql挪到awr repository的基表wrh$_sql_plan中时没有保留v$sql_plan中记录谓词条件(包括驱动查询条件和过滤查询条件)的列ACCESS_PREDICATES和FILTER_PREDICATES的值,所以不是DBMS_XPLAN.DISPLAY_CURSOR不想显示谓词条件,而是根本就没有谓词条件可供其显示。
2.3、autotrace开关
在sqlplus中将autotrace开关打开也能得到目标sql的执行计划,而且除此之外还能得到目标sql在执行时的资源消耗量,即通过设置autotrace开关我们可以额外观察到目标sql执行时所消耗的物理读,逻辑读,产生redo的数量以及排序的数量等。
设置autotrace开发语法如下:
set autotrace OFF|ON|TRACEONLY
[explan]
[statistics]
(1)在sqlplus的当前session中执行命令set autotrace on,可以将autotrace开发完全打开,在这个session中随后执行的所有sql除了显示sql执行结果之外,还会额外显示这个sql对应的执行计划和资源消耗情况。
(2)在sqlplus的当前session执行命令set autotrace off,可以在当前的session中将autotrace开关关闭,在这个session中随后执行的结果只显示执行结果,autotrace开关默认值是OFF。
(3)在sqlplus的当前session中执行命令set autotrace traceonly,可以在当前session中将autotrace开关以不显示sql执行结果的具体内容的方式完全打开。这种方式与st autotrace on的唯一区别就在于,对应traceonly而言,Oracle只会显示sql执行结果的数量,而不会显示直接结果的具体内容。所以适用于那些sql执行结果的具体内容特别长,会连续刷屏的sql,这种情况下我们往往并不关心这些sql的执行结果的具体内容,而只是关心他们的执行计划和资源消耗情况。
(4)在sqlplus的当前session中执行命令set autotrace traceonly explain,可以在挡在session中将autotrace开关以只显示执行技术的方式打开。这种方式与set autotrace traceonly的区别就在于,不会显示目标sql的资源消耗量和执行结果数量,而只显示执行计划。
(5)在sqlplus的当前session中执行命令set autotrace traceonly statistics,可以在当前session中将autotrace开关以只显示sql的资源消耗量的方式打开,这种方式与set autotrace traceonly的唯一区别在于,不显示目标sql的执行计划,而只会显示目标sql执行结果的数量和资源消耗情况。
Oracle有如下简写:
autotrace可以简写成autot
traceonly----trace
explan-------exp
statistics-----stat
按照上述简写规则,如下的写法都是等价的:
SET AUTOTRACE ON==SET AUTOT ON
SET AUTOTRACE OFF ==SET AUTOT OFF
SET AUTOTRACE TRACEONLY ==SET AUTOT TRACE
SET AUTOTRACE TRACEONLY EXPLAIN ==SET AUTOT TRACE EXP
SET AUTOTRACE TRACEONLY STATISTICS ==SET AUTOT TRACE STAT
2.4、10046时间和tkprof命令
使用10046事件是在Oracle数据库中查看目标SQL的执行计划的另一种方法,这种方法与使用explain plan命令、DBMS_XPLAN包和AUTOTRACE开关的不同之处在于,所得到的执行计划中明确显示了目标SQL实际执行计划中每一个执行步骤所消耗的逻辑读、物理读和花费的时间。这种细粒度的明显显示在我们诊断复杂SQL的性能问题时尤为有用,而且这也是其他三种方法所不能提供的(实际上,用GATHER_PLAN_STATISTICS Hint配合DBMS_XPLAN包一起使用也可以达到类似10046事件这种细粒度的明细显示效果)。执行10046事件的步骤:
a)首先在当前session中激活10046事件
b)接着在此session中执行目标SQL
c)最后在此session中关闭10046事件
当执行完上述步骤后,Oracle就会将目标SQL的执行计划和明细资源消耗写入此session所对应的trace文件中,查看这个trace文件就能知道目标sql的执行计划和资源消耗明细,Oracle会在参数USER_DUMP_DEST所代表的目录下生产这个trace文件,其命名格式为"实例名_ora_当前session的spid.trc",例如oratest_ora_219.trc。通常可以使用如下这两种方法在当前session中激活10046事件:
在当前session中执行alter session set events '10046 trace name context forever,level 12';
在当前session中执行oradebug event 10046 trace name context forever,level 12
上述命令的关键字level后的数字是表示设置的10046事件的level值,这个值是可以修改的,我们通常使用的值为12,表示在产生的trace文件中除了有目标SQL的执行计划和资源消耗明细之外,还会包含目标SQL所使用的绑定变量的值以及该session所经历的等待事件,除了上述LEVEL值之外,其他部分都是固定的语法。这里我们推荐使用第二种方法,因为可以在激活10046事件后执行命令oradebug tracefile_name来得到当前session所对应的trace文件的具体路径和名称。
对应的,在当前session中关闭10046事件的两种方法为:
在当前session中执行:
alter session set events '10046 trace name context off';
oradebug event 10046 trace name context off;
这里需要注意的是,10046事件所产生的原始trace文件我们习惯称之为裸trace文件(new trace),Oracle记录在裸trace文件中的内容一眼看上去并不是只管,也不是那么容易能看懂,为了让上述裸trace文件能够以一种更直观、更容易懂的方式展现出来,Oracle提供了tkprof命令,这个命令是Oracle自带的,可以用它来翻译上述裸trace文件,从随后的示例中可以看到翻译后的内容确实更直观。
示例:
oradebug setmypid ----表示对当前session使用oradebug命令
oradebug event 10046 trace name context forever,level 12; --打开10046事件
select empno from scott.emp; --目标SQL
oradebug tracefile_name --显示trace文件路径
oradebug event 10046 trace name context off; --关闭10046事件
开启另外一个窗口:
tkprof d:\app\administrator\diag\rdbms\ortest\ortest\trace\ortest_ora_7784.trc
output = d:\app\20211213_tkprof.tra
即可查看编译后的文件。
3、如何得到真实的执行计划
在上面介绍了四种方法,除了第四种方法外,其他三种方法得到的执行计划都有可能是不准确的。在Oracle数据库中判断得到的执行计划是否准确,就是看目标SQL是否真正执行,真正执行过的SQL所对应的执行计划就是准的,反之则可能不准。注意,这里的判断原则从严格意义上来说并不适用于AUTOTRACE开关,因为所有使用AUTOTRACE开关显示的执行计划都有可能是不准的,即使对应的目标SQL实际上已经执行过,这一点在后会详细解释。
下面我们就用上述原则来判断除了第4中以外的其他三种方法中哪些方法得到的执行计划是准的,哪些是可能不准的。
对使用第一种方法(EXPLAIN PLAN)得到的执行计划而言,因为此时目标SQL并没有实际执行,所以用该方法得到的执行计划有可能是不准的,尤其是在目标SQL包含绑定变量时,在默认开启绑定变量窥探(Bind Peeking)情况下,对含有绑定变量的目标SQL使用explain plan得到的执行计划只是一个半成品,Oracle在随后对该SQL的绑定变量进行窥探后就得到额这些绑定变量具体的值,此时Oracle很可能会对上述半成品的执行计划做调整,一旦做了调整,使用EXPAIN PLAN命令得到的执行计划就不准了。
对于使用第二种方法(DBMS_XPLAN包)而言,针对不同的应用场景,你可以选择以下的一种:
select * from table(DBMS_XPLAN.display);
select * from table(DBMS_XPLAN.display_cursor(null,null,'advanced'));
select * from table(dbma_xplan.display_cursor('sql_id/hash_value',child_cursor_number,'advanced'));
select * from table(dbms_xplan.display_awr('sql id'));
显然select * from table(DBMS_XPLAN.display);所得到的执行计划可能是不准的。因为它知识用于查看使用expain plan命令得到的执行计划,目标sql此时还没有真正执行,所以用它得到的执行计划可能是不准的。使用剩下三种方式所得到的执行计划都是准的。因为此时SQL都已经被实际执行过。
对使用第三种方法(AUTO TRACE开关),可以使用如下三种方式中的一种开启AUTO TRACE开关:
set autotrace on
set autotrace traceonly
set autotrace traceonly explan
上述三种方式中,当使用set autotrace on和set autotrace traceonly时,SQL都已经被实际执行过了,真是因为被实际执行过,所以在此情况下我们能扩大农目标SQL的实际资源消耗情况。当使用set autotrace traceonly explan时,如果执行的是select语句,则该select语句并没有被Oracle实际执行,但如果执行的是DML语句,情况就不一样了,此时的DML语句是会被实际执行的。所以在使用上面三种方法来获得DML语句的执行计划要小心,因为这些DML语句实际上已经被执行了。
这里需要特别注意的是:虽然使用部分SET AUTOTRACE命令后SQL实际上已经被执行了,但是所有使用SET AUTOTRACE命令所得到的执行计划都有可能是不准的,因为autotrace命令所显示的执行计划都是来源于调用expain plan命令。
- Oracle中获取执行计划的几种方法分析
以下是对Oracle中获取执行计划的几种方法进行了详细的分析介绍,需要的朋友可以参考下 1. 预估执行计划 - Explain PlanExplain plan以SQL语句作为输入,得到这条S ...
- ORACLE 获取执行计划的方法
一.获取执行计划的6种方法(详细步骤已经在每个例子的开头注释部分说明了): 1. explain plan for获取: 2. set autotrace on : 3. statistics_lev ...
- oracle获取执行计划及优缺点 详解
一.获取执行计划的6种方法(详细步骤已经在每个例子的开头注释部分说明了):1. explain plan for获取: 2. set autotrace on : 3. statistics_leve ...
- 获取执行计划——EXPLAN PLAN
一般获取执行计划有四种途径:1.执行explain plan,查询结果输出表.2.查询动态性能视图,它显示缓存在库缓存中的执行计划(有时查不出结果是因为执行计划已经不在库缓存中).3.查询AWR或St ...
- 案例:使用dbms_xplan.display_cursor无法获取执行计划
案例:使用dbms_xplan.display_cursor无法获取执行计划 环境:RHEL 6.5 + Oracle 11.2.0.4 在一次测试中发现使用dbms_xplan.display_cu ...
- 查看Oracle数据库中的执行计划
1.set autotrace traceonly命令 2.explain plan for命令 1)explain plan for select * from dual; 2)select * f ...
- oracle中获取执行计划
1. 预估执行计划 - Explain PlanExplain plan以SQL语句作为输入,得到这条SQL语句的执行计划,并将执行计划输出存储到计划表中. 首先,在你要执行的SQL语句前加expla ...
- Oracle(一)执行计划
目录 一.什么是执行计划 二.如何查看执行计划 三.如何读懂执行计划 1. 执行顺序的原则 2. 执行计划中字段解释 3. 谓词说明 4. JOIN方式 4.1 HASH JOIN(散列连接) 4.2 ...
- Oracle性能优化之oracle中常见的执行计划及其简单解释
一.访问表执行计划 1.table access full:全表扫描.它会访问表中的每一条记录(读取高水位线以内的每一个数据块). 2.table access by user rowid:输入源ro ...
- oracle 基础知识(十三)----执行计划
一, 执行计划是什么? 一条查询语句在ORACLE中的执行过程或访问路径的描述.即就是对一个查询任务,做出一份怎样去完成任务的详细方案. 二,执行计划的查看 设置autotrace 序号 命令 解释 ...
随机推荐
- js循环判断创建新对象放数组中
原效果 之后效果: <!doctype html> <html lang="en"> <head> <meta charset=" ...
- Postgresql 全局索引与分区索引对于SQL性能影响的比较及DDL操作后分区全局索引是否会失效
Postgresql 提供了对于分区表 global index 的支持.global index 不仅提供了对于唯一索引功能的改进(无需包含分区键),而且在性能上相比非global index (l ...
- LeetCode-2038 如果相邻两个颜色均相同则删除当前颜色
来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/remove-colored-pieces-if-both-neighbors-are-the-s ...
- java.sql.SQLException: Access denied for user ‘root‘@‘localhost‘ (using password: YES)问题
此报错大多数存在的问题为mysql密码错误,需要去JDBC文件中寻找url查看是否密码错误.
- js数字取整的方法
parseInt(123.34)=123(保留整数) Math.ceil(123.34)=124(向上取整) Math.floor(123.34)=123(向下取整) Math.round(123.3 ...
- 新的学习历程-python5 输入输出基础
1 uname=input("please input username:") 2 print("welcome",uname) #print各项间默认以空格作 ...
- Excel之VLOOKUP()函数的基本用法
语法: VLOOKUP(lookup_value,table_array,col_index_num,[range_lookup]) 规则: 注意: 查找的值:内容需要完全一样 查找范围:查找范围的 ...
- Linux系统Shell脚本第三章:for、while循环及脚本实操
目录 一.echo命令 二.查看当前系统的时间-date命令 三.for循环语句 四.while循环语句结构(迭代) 五.until 循环语句结构 六.continue和break 一.echo命令 ...
- git remote prune origin删除本地有但在远程库已经不存在的分支
先调用git remote show origin 该命令能够获取远端分支信息,你可以看到和本地和远端不同步的地方: 过时的就是和本地不同步的分支,本地已过时的表示你需要移除这个分支了. 这个时候你需 ...
- 关于 MySQL 的 General Log 功能
检查 General Log 输出目标 SHOW GLOBAL VARIABLES LIKE 'log_output'; # Type: Set # Default Value: FILE # Val ...