[Oracle] 获取运行计划的各方法总结
总的结论:
一.获取运行计划的6种方法(具体步骤已经在每一个样例的开头凝视部分说明了):
1. explain plan for获取;
2. set autotrace on 。
3. statistics_level=all;
4. 通过dbms_xplan.display_cursor输入sql_id參数直接获取
5. 10046 trace跟踪
6. awrsqrpt.sql
二.适用场合分析
1.假设某SQL运行很长时间才会出结果。甚至慢到返回不了结果,这时候看运行计划就仅仅能用方法1,或者方法4调用现成的。
2.跟踪某条SQL最简单的方法是方法1,其次就是方法2。
3.假设想观察到某条SQL有多条运行计划的情况。仅仅能用方法4和方法6;
4.假设SQL中含有多函数,函数中套有SQL等多层递归调用,想准确分析。仅仅能用法5。
5.要想确保看到真实的运行计划,不能用方法1和方法2;
6.要想获取表被訪问的次数。仅仅能用法3;
环境构造
--研究Nested Loops Join訪问次数前准备工作
DROP TABLE t1 CASCADE CONSTRAINTS PURGE;
DROP TABLE t2 CASCADE CONSTRAINTS PURGE;
CREATE TABLE t1 (
id NUMBER NOT NULL,
n NUMBER,
contents VARCHAR2(4000)
)
;
CREATE TABLE t2 (
id NUMBER NOT NULL,
t1_id NUMBER NOT NULL,
n NUMBER,
contents VARCHAR2(4000)
)
;
execute dbms_random.seed(0);
INSERT INTO t1
SELECT rownum, rownum, dbms_random.string('a', 50)
FROM dual
CONNECT BY level <= 1000
ORDER BY dbms_random.random;
INSERT INTO t2 SELECT rownum, rownum, rownum, dbms_random.string('b', 50) FROM dual CONNECT BY level <= 100000
ORDER BY dbms_random.random;
COMMIT;
CREATE INDEX t1_n ON t1 (n);
CREATE INDEX t2_t1_id ON t2(t1_id);
以下我们将会用多种方法来查看例如以下语句的运行计划
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
方法1(explain plan for 的方式。
类似PLSQL DEVELOPE里的F5)
步骤1:explain plan for "你的SQL"
步骤2:select * from table(dbms_xplan.display());
set linesize 1000
set pagesize 2000
explain plan for
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
select * from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 3532430033
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 8138 | 6 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 2 | 8138 | 6 (0)| 00:00:01 |
| 3 | INLIST ITERATOR | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 2 | 4056 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | T1_N | 1 | | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | T2_T1_ID | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | T2 | 1 | 2041 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("T1"."N"=18 OR "T1"."N"=19)
6 - access("T1"."ID"="T2"."T1_ID")
Note
-----
- dynamic sampling used for this statement (level=2) 已选择24行。
长处: 1.无需真正运行。快捷方便
缺陷: 1.没有输出执行时的相关统计信息(产生多少逻辑读,多少次递归调用,多少次物理读的情况)。
2.无法推断是处理了多少行;
3.无法推断表被訪问了多少次。
确实啊,这毕竟都没有真正执行又怎样得知真实执行产生的统计信息。
方法2(set autotrace on 方式)
步骤1:set autotrace on
步骤2:在此处运行你的SQL就可以,兴许自然会有结果输出
另,有例如以下几种方式:
set autotrace on (得到执行计划,输出执行结果)
set autotrace traceonly (得到执行计划,不输出执行结果)
set autotrace traceonly explain (得到运行计划,不输出运行结果和统计信息部分,仅展现运行计划部分)
set autotrace traceonl statistics(不输出执行结果和执行计划部分,仅展现统计信息部分)
set autotrace on
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19); 运行计划
----------------------------------------------------------
Plan hash value: 3532430033
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 8138 | 6 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 2 | 8138 | 6 (0)| 00:00:01 |
| 3 | INLIST ITERATOR | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 2 | 4056 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | T1_N | 1 | | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | T2_T1_ID | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | T2 | 1 | 2041 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("T1"."N"=18 OR "T1"."N"=19)
6 - access("T1"."ID"="T2"."T1_ID")
Note
-----
- dynamic sampling used for this statement (level=2)
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
1032 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed
长处:1.能够输出执行时的相关统计信息(产生多少逻辑读,多少次递归调用,多少次物理读的情况);
2.尽管必需要等语句运行完成后才干够输出运行计划。可是能够有traceonly开关来控制返回结果不打屏输出。
缺陷:1.必需要等到语句真正运行完成后。才干够出结果;
2.无法看到表被訪问了多少次。
方法3(statistics level=all的方式)
步骤1:alter session set statistics_level=all ;
步骤2:在此处运行你的SQL
步骤3:select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
另注:
1. 假设你用 /*+ gather_plan_statistics */的方法,能够省略步骤1,直接步骤2,3。
2. keyword解读(当中OMem、1Mem和User-Mem在兴许的课程中会陆续见到):
Starts为该sql运行的次数。
E-Rows为运行计划估计的行数。
A-Rows为实际返回的行数。A-Rows跟E-Rows做比較。就能够确定哪一步运行计划出了问题。
A-Time为每一步实际运行的时间(HH:MM:SS.FF),依据这一行能够知道该sql耗时在了哪个地方。
Buffers为每一步实际运行的逻辑读或一致性读。
Reads为物理读。
OMem:当前操作完毕全部内存工作区(Work Aera)操作所总共使用私有内存(PGA)中工作区的大小,
这个数据是由优化器统计数据以及前一次运行的性能数据估算得出的
1Mem:当工作区大小无法满足操作所需的大小时,须要将部分数据写入暂时磁盘空间中(假设仅须要写入一次就能够完毕操作,
就称一次通过,One-Pass;否则为多次通过,Multi_Pass).该列数据为语句最后一次运行中,单次写磁盘所须要的内存
大小,这个由优化器统计数据以及前一次运行的性能数据估算得出的
User-Mem:语句最后一次运行中,当前操作所使用的内存工作区大小,括号中面为(发生磁盘交换的次数,1次即为One-Pass,
大于1次则为Multi_Pass,假设没有使用磁盘,则显示OPTIMAL)
OMem、1Mem为运行所需的内存评估值,0Mem为最优运行模式所需内存的评估值。1Mem为one-pass模式所需内存的评估值。
0/1/M 为最优/one-pass/multipass运行的次数。Used-Mem耗的内存
set autotrace off
alter session set statistics_level=all ;
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
SQL_ID 1a914ws3ggfsn, child number 0
-------------------------------------
SELECT * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n in(18,19) Plan hash value: 3532430033
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 2 |00:00:00.01 | 12 |
| 1 | NESTED LOOPS | | 1 | | 2 |00:00:00.01 | 12 |
| 2 | NESTED LOOPS | | 1 | 2 | 2 |00:00:00.01 | 10 |
| 3 | INLIST ITERATOR | | 1 | | 2 |00:00:00.01 | 5 |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 2 | 2 | 2 |00:00:00.01 | 5 |
|* 5 | INDEX RANGE SCAN | T1_N | 2 | 1 | 2 |00:00:00.01 | 3 |
|* 6 | INDEX RANGE SCAN | T2_T1_ID | 2 | 1 | 2 |00:00:00.01 | 5 |
| 7 | TABLE ACCESS BY INDEX ROWID | T2 | 2 | 1 | 2 |00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access(("T1"."N"=18 OR "T1"."N"=19))
6 - access("T1"."ID"="T2"."T1_ID")
Note
-----
- dynamic sampling used for this statement (level=2) 已选择29行。
长处:1.能够清晰的从STARTS得出表被訪问多少。
2.能够清晰的从E-ROWS和A-ROWS中得到预測的行数和真实的行数。从而能够准确推断Oracle评估是否准确。
3.尽管没有专门的输出执行时的相关统计信息,可是执行计划中的BUFFERS就是真实的逻辑读的多少
缺陷:1.必需要等到语句真正运行完成后。才干够出结果。
2.无法控制记录输屏打出。不像autotrace有 traceonly 能够控制不将结果打屏输出。
3.看不出递归调用的次数。看不出物理读的多少(只是逻辑读才是重点)
方法4(知道sql_id后。直接带入的方式,简单,就步骤1)
步骤1: select * from table(dbms_xplan.display_cursor('&sq_id')); (该方法是从共享池里得到)
注:
1. 另一个方法,select * from table(dbms_xplan.display_awr('&sq_id'));(这是awr性能视图里获取到的)
2. 假设有多运行计划,能够用类似方法查出
select * from table(dbms_xplan.display_cursor('cyzznbykb509s',0));
select * from table(dbms_xplan.display_cursor('cyzznbykb509s',1));
select * from table(dbms_xplan.display_cursor('1a914ws3ggfsn'));
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
SQL_ID 1a914ws3ggfsn, child number 0
-------------------------------------
SELECT * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n in(18,19) Plan hash value: 3532430033
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 6 (100)| |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 2 | 8138 | 6 (0)| 00:00:01 |
| 3 | INLIST ITERATOR | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 2 | 4056 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | T1_N | 1 | | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | T2_T1_ID | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | T2 | 1 | 2041 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
--------------------------------------------------- 5 - access(("T1"."N"=18 OR "T1"."N"=19))
6 - access("T1"."ID"="T2"."T1_ID") Note
-----
- dynamic sampling used for this statement (level=2)
长处:1.知道sql_id马上可得到运行计划。和explain plan for 一样无需运行;
2.能够得到真实的运行计划。(停。等等,啥真实的,刚才这几个套路中,还有假的运行计划的吗?)
缺陷: 1.没有输出执行时的相关统计信息(产生多少逻辑读,多少次递归调用,多少次物理读的情况);
2.无法推断是处理了多少行;
3.无法推断表被訪问了多少次。
方法5(10046TRACE)
步骤1:alter session set events '10046 trace name context forever,level 12'; (开启跟踪)
步骤2:运行你的语句
步骤3:alter session set events '10046 trace name context off'; (关闭跟踪)
步骤4:找到跟踪后产生的文件
步骤5:tkprof trc文件 目标文件 sys=no sort=prsela,exeela,fchela (格式化命令)
set autotace off
alter session set statistics_level=typical;
alter session set events '10046 trace name context forever,level 12'; SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19); alter session set events '10046 trace name context off';
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; exit tkprof d:\oracle\diag\rdbms\test11g\test11g\trace/test11g_ora_2492.trc d:\10046.txt sys=no sort=prsela,exeela,fchela SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19) 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 12 0 2
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 12 0 2 Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 94 Rows Row Source Operation
------- ---------------------------------------------------
2 NESTED LOOPS (cr=12 pr=0 pw=0 time=0 us)
2 NESTED LOOPS (cr=10 pr=0 pw=0 time=48 us cost=6 size=8138 card=2)
2 INLIST ITERATOR (cr=5 pr=0 pw=0 time=16 us)
2 TABLE ACCESS BY INDEX ROWID T1 (cr=5 pr=0 pw=0 time=0 us cost=2 size=4056 card=2)
2 INDEX RANGE SCAN T1_N (cr=3 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 108621)
2 INDEX RANGE SCAN T2_T1_ID (cr=5 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 108622)
2 TABLE ACCESS BY INDEX ROWID T2 (cr=2 pr=0 pw=0 time=0 us cost=2 size=2041 card=1) Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 2 0.00 0.00
SQL*Net message from client
长处:1.能够看出SQL语句相应的等待事件
2.假设SQL语句中有函数调用,SQL中有SQL,将会都被列出,无处遁形。
3.能够方便的看出处理的行数,产生的物理逻辑读。
4.能够方便的看出解析时间和运行时间。
5.能够跟踪整个程序包
缺陷: 1.步骤繁琐。比較麻烦
2.无法推断表被訪问了多少次。
3.运行计划中的谓词部分不能清晰的展现出来。
方法6. awrsqrpt.sql
步骤1:@?/rdbms/admin/awrsqrpt.sql
步骤2:选择你要的断点(begin snap 和end snap)
步骤3:输入你的sql_id
[Oracle] 获取运行计划的各方法总结的更多相关文章
- 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 ...
- 使用hint优化Oracle的运行计划 以及 SQL Tune Advisor的使用
背景: 某表忽然出现查询很缓慢的情况.cost 100+ 秒以上:严重影响生产. 原SQL: explain plan for select * from ( select ID id,RET_NO ...
- oracle分区表运行计划
分区表有非常多优点,以大化小,一小化了,加上并行的使用,在loap中能往往能提高几十倍甚至几百倍的效果. 当然表设计得不好也会适得其反.效果比普通表跟糟糕. 为了更好的使用分区表,这里看一下分区表的运 ...
- 查询oracle sql运行计划,一个非常重要的观点--dba_hist_sql_plan
该文章的作者给予了极大的帮助长老枯荣,为了表达我的谢意. 这适用于oracle db版本号oracle 10g或者更高的版本号. 之所以说这种看法是非常重要的,因为观点是有之一awrsqrpt报告没有 ...
- Oracle获取当前session ID的方法
1.使用v$mystat视图获取当前session的ID select sid from v$mystat; 2.使用userenv内部函数获取当前session的ID select userenv( ...
- ORACLE 获取程序当前位置的方法
FUNCTION f_Get_Program_Position RETURN VARCHAR2 IS l_Owner ); l_Name ); l_Lineno NUMBER; l_Type ); B ...
- Oracle中获取执行计划的几种方法分析
以下是对Oracle中获取执行计划的几种方法进行了详细的分析介绍,需要的朋友可以参考下 1. 预估执行计划 - Explain PlanExplain plan以SQL语句作为输入,得到这条S ...
- ORACLE获取SQL绑定变量值的方法总结
本文总结一下ORACLE数据库中如何获取SQL绑定变量值的方法,在SQL优化调优过程中,经常会用到这方面的知识点.在此梳理.总结一下,方面日后查找.翻阅. 方法1:查询V$SQL V$SQL视图中 ...
随机推荐
- 基于ubuntu 14.04 kvm虚拟化部署
1. 宿主机环境(dell备份服务器) Ubuntu 14.04 LTS 64位 内存:16G 硬盘:2T 2. 确认CPU是否支持硬件虚拟化 root@shwilling:~# egrep -o ' ...
- python:post请求业务、调用微信api监控业务
vim post.py #!/usr/bin/env python # -*- coding: utf-8 -*- import json import os import datetime impo ...
- Web框架之Django_05 模型层了解(单表查询、多表查询、聚合查询、分组查询)
摘要: 单表查询 多表查询 聚合查询 分组查询 一.Django ORM 常用字段和参数: 常用字段:#AutoFieldint自增列,必须填入参数primary_key = True,当model中 ...
- Day10文件内指针移动和函数
强调:只有t模式下的read(n),n代表字符个数,除此以外都是以字节为单位 ,例如f.read(4)读出4个字符 控制文件内指针的移动:f.seek()以字节为单位 f.tell()文件开头为准,当 ...
- JavaScript正则表达式-重复次数(数量词)
*:表示对前面表达式的匹配出现零次或多次. var reg_pattern = /bo*/;//匹配b.bo.boooo +:表示对前面表达式的匹配连续出现一次或多次. var reg_pattern ...
- PAT Basic 1030
1030 完美数列 给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列. 现在给定参数p和一些正整数,请你从中选择尽可能多的数 ...
- Mysql 使用命令及 sql 语句示例
Mysql 是数据库开发使用的主要平台之一.sql 的学习掌握与使用是数据库开发的基础,此处展示详细sql 语句的写法,及各种功能下的 sql 语句. 在此处有 sql 语句使用示例:在这里 此处插入 ...
- 关于MongoDB分布式高可用集群实现
一.环境准备 1.本例使用3台Linux主机,IP地址如下: 点击(此处)折叠或打开 Server B Server C 2.根据需要,开启相应主机防火墙的相关端口.本次需要用到3台主机,所以开启这3 ...
- vue elementUI 表单校验(数组多层嵌套)
在使用vue element-ui form表单渲染的时候,会遇到这样的数据结构: { "title":''123455, "email":'123456@qq ...
- 数字梯形(cogs 738)
«问题描述:给定一个由n 行数字组成的数字梯形如下图所示.梯形的第一行有m 个数字.从梯形的顶部的m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径.规则1:从梯形的顶 ...