通过dbms_xplan.display_cursor识别低效的执行计划
dbms_xplan.display_cursor定义:
function display_cursor(sql_id varchar2 default null,
cursor_child_no integer default 0,
format varchar2 default 'TYPICAL')
return dbms_xplan_type_table
pipelined;
识别问题sql我们可以通过以下几种方式获得:
1. AWR
2. ASH
3. 根据当时占用CPU高的进程查找对应的sql
问题sql找到了,接着我们要看sql的执行计划,但问题是如果快速找到执行计划中哪个地方出了问题呢?
如果我们能得到sql执行时每一步实际返回的行数,就可以跟执行计划预计返回的行数做比较,两者数据相差不大,可以认为执行计划没有问题;反之,两者差距悬殊,就表示执行计划出了问题。
从10g开始oracle提供了dbms_xplan包的display_cursor函数,来同时显示执行计划预期返回的行数和实际返回的行数,于是我们可以利用这个包来快速找到执行计划中哪个地方出了问题,然后对症采取办法。
dbms_xplan包的display_cursor函数是从libary cache中获取执行计划,所以要想访问该函数,必须先授予权限:grant select any dictionary to scott;
使用dbms_xplan.display_cursor函数的步骤是:
1. 设置初始化参数statistics_level为ALL,如下:
SQL> alter session set statistics_level='ALL';
statistics_level控制数据库收集统计信息的级别,有三个值:
BASIC :收集基本的统计信息
TYPICAL:收集大部分统计信息(数据库的默认设置)
ALL:收集全部统计信息
2. 执行问题sql,如:
SQL> select ename,sal from emp,dept where emp.deptno=dept.deptno and dept.loc='CHICAGO';
3. 使用dbms_xplan.display_cursor包,查看带实际返回行的执行计划:
set lines 300
set pages 9000
SQL> select * from table(dbms_xplan.display_cursor(null,0,'allstats last'));
dbms_xplan.display_cursor函数的定义是:
-- display from V$SQL_PLAN (or V$SQL_PLAN_STATISTICS_ALL)
function display_cursor(sql_id varchar2 default null,
cursor_child_no integer default 0,
format varchar2 default 'TYPICAL')
return dbms_xplan_type_table
pipelined;
其中参数sql_id为父游标,如果为null,表示显示该会话之前的sql执行计划。cursor_child_no为子游标的序号,默认为0,如果设定为NULL,则所有该父游标下所有的子游标的执行计划都将返回。
参数format指定要显示哪些信息,常用的有:iostats(i/o信息显示)、allstats(i/o信息显示+pga信息)、advanced(显示所有统计信息)、iostats last或allstats last(只显示最后一次执行的统计信息)。默认值TYPICAL只能显示一个普通的执行计划,不能显示出实际返回的行。
第3步的输出为:
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID cuq0vs99sctnm, child number 0
-------------------------------------
select ename,sal from emp,dept where emp.deptno=dept.deptno and
dept.loc='CHICAGO'
Plan hash value: 844388907
-----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 6 |00:00:00.01 | 11 | | | |
| 1 | MERGE JOIN | | 1 | 4 | 6 |00:00:00.01 | 11 | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 1 | 1 |00:00:00.01 | 4 | | | |
| 3 | INDEX FULL SCAN | PK_DEPT | 1 | 4 | 4 |00:00:00.01 | 2 | | | |
|* 4 | SORT JOIN | | 1 | 14 | 6 |00:00:00.01 | 7 | 2048 | 2048 | 2048 (0)|
| 5 | TABLE ACCESS FULL | EMP | 1 | 14 | 14 |00:00:00.01 | 7 | | | |
-----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("DEPT"."LOC"='CHICAGO')
4 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
filter("EMP"."DEPTNO"="DEPT"."DEPTNO")
25 rows selected.
解读以上输出:
Starts为该sql执行的次数。
E-Rows为执行计划预计的行数。
A-Rows为实际返回的行数。A-Rows跟E-Rows做比较,就可以确定哪一步执行计划出了问题。
A-Time为每一步实际执行的时间(HH:MM:SS.FF),根据这一行可以知道该sql耗时在了哪个地方。
Buffers为每一步实际执行的逻辑读或一致性读。
Reads为物理读。
OMem、1Mem为执行所需的内存评估值,0Mem为最优执行模式所需内存的评估值,1Mem为one-pass模式所需内存的评估值。
0/1/M 为最优/one-pass/multipass执行的次数。
查找低效执行计划:
1.比较A-Rows/Starts跟E-Rows,如果两值差别悬殊,则该行是低效执行计划。
2.查看Buffers/A-rows的比率,即返回一行平均消耗多少逻辑读
Buffers/A-rows<5 表示访问路径不错
Buffers/A-rows between 10 and 15,表示访问路径可以接受
Buffers/A-rows>15or20,表示路径不好,该行是低效执行计划,可以优化
另一种使用dbms_xplan.display_cursor函数的步骤是:
1. 在问题sql中加入提示:gather_plan_statistics
SQL> select /*+ gather_plan_statistics */ ename,sal from emp,dept where emp.deptno=dept.deptno and dept.loc='CHICAGO';
2. 使用dbms_xplan.display_cursor包,查看带实际返回行的执行计划:
set lines 300
set pages 9000
SQL> select * from table(dbms_xplan.display_cursor(null,0,'allstats last'));
根据dbms_xplan.display_cursor函数可以很轻易地找到执行计划的哪个地方出了问题,接着我们就来分析CBO做出错误执行计划的原因。
如果出问题的那一步对应的是个索引,我们可以根据以下sql来判断是否统计信息出了问题:
0. 检查是否是索引碎片造成的
exec p_show_space('索引名', '索引属主', 'index')
1. 查看该索引的统计信息:
select index_name,num_rows,distinct_keys,num_rows/distinct_keys as avg_rows_per_key,last_analyzed from user_indexes where index_name='索引名'; 如下:
SQL> select index_name,num_rows,distinct_keys,num_rows/distinct_keys avg_rows_per_key,last_analyzed from user_indexes where index_name='PK_DEPT';
2. 查看实际的数据
select count(*) num_rows,count(nullif(col1,列值)) distinct_keys, count(distinct 列名) avg_rows_per_key from 表名; 如下:
SQL> select count(*) num_rows,count(nullif(loc,'CHICAGO')) distinct_keys,count(distinct 'CHICAGO') avg_rows_per_key from dept;
如果上面两步前两列数据差别悬殊,则说明统计信息不准确,需要重新收集统计信息;如果前两列数据相差不大,第三列数据是number,且相差很大,则可能索引所在列的直方图出了问题。
3. 查看索引列是否做了直方图统计
alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
select column_name,histogram,num_buckets,last_analyzed from user_tab_cols where table_name='EMP' and column_name in ('EMPNO','ENAME');
COLUMN_NAME HISTOGRAM NUM_BUCKETS LAST_ANALYZED
------------------------------ --------------- ----------- -------------------
EMPNO NONE 1 2012-10-23 22:48:28
ENAME HEIGHT BALANCED 16 2012-10-23 22:48:28
histogram列为NONE则表示未收集直方图。
直方图收集:
method_opt参数取值: size 1不搜集,size 2~255会搜集,size auto自动判断,size skewonly只要数据倾斜则收集。method_opt参数默认值为for all columns size auto,oracle自己决定采样比率。发现此默认值有时收集的直方图很有限,必要时可对所有索引列收集直方图 (不建议对所有列收集直方图,因为这样会导致存储直方图信息的表sys.histgrm$过大)
SQL> exec dbms_stats.gather_table_stats(user,'DEPT',method_opt =>'for all indexed columns',cascade=>true)
以下为个人牵强补充:
如果出问题的那一步对应的是个表,我们可以根据以下sql来判断是否统计信息出了问题:
1. 查看该表的统计信息及碎片率:
SQL> select num_rows from user_tables where table_name='EMP';
select num_rows,avg_row_len*num_rows/1024/blocks*8*100 碎片率 from user_tables where table_name='T'; --这种计算碎片率的方式仅适用于默认参数storage(initial 64K)建立的表
或用exec p_show_space('表名', '表属主', 'table')
2. 查看实际的数据
SQL> select count(*) num_rows from emp;
收集表的统计信息:exec dbms_stats.gather_table_stats(user,'表名',cascade=>true) --cascade=>true表示同时收集索引
http://pandarabbit.blog.163.com/blog/static/209284144201292910217427/
http://blog.csdn.net/dbanote/article/details/24516037
通过dbms_xplan.display_cursor识别低效的执行计划的更多相关文章
- 使用 dbms_xplan.display 按照 plan_hash_value 查执行计划的方法
dbms_xplan.display_* 能按照 plan_hash_value 只有 display_awr 方法,如果这个SQL PLAN 刚刚生成,没有写入到AWR怎么办呢? 可以将 V$SQL ...
- Oracle查看SQL执行计划的方式
Oracle查看SQL执行计划的方式 获取Oracle sql执行计划并查看执行计划,是掌握和判断数据库性能的基本技巧.下面案例介绍了多种查看sql执行计划的方式: 基本有以下几种方式: ...
- ORACLE数据库中执行计划出现INTERNAL_FUNCTION一定是隐式转换吗?
ORACLE数据库中,我们会使用一些SQL语句找出存在隐式转换的问题SQL,其中网上流传的一个SQL语句如下,查询V$SQL_PLAN的字段FILTER_PREDICATES中是否存在INTERNAL ...
- Oracle执行计划学习笔记
目录 一.获取执行计划的方法 (1) explain plan for (2) set autotrace on (3) statistics_level=all (4) dbms_xplan.dis ...
- 基于Oracle的SQL优化(崔华著)-整理笔记-第2章“Oracle里的执行计划”
详细介绍了Oracle数据里与执行计划有关的各个方面的内容,包括执行计划的含义,加何查看执行计划,如何得到目标SQL真实的执行计划,如何查看执行计划的执行顺序,Oracle数据库里各种常见的执行计划的 ...
- SELECT TOP 1 比不加TOP 1 慢的原因分析以及SELECT TOP 1语句执行计划预估原理
本文出处:http://www.cnblogs.com/wy123/p/6082338.html 现实中遇到过到这么一种情况: 在某些特殊场景下:进行查询的时候,加了TOP 1比不加TOP 1要慢(而 ...
- dbms_xplan的display_cursor查看执行计划
准备工作: SQL> conn sys/root as sysdba Connected. SQL> grant select on v_$sql_plan to scott; Grant ...
- 案例:使用dbms_xplan.display_cursor无法获取执行计划
案例:使用dbms_xplan.display_cursor无法获取执行计划 环境:RHEL 6.5 + Oracle 11.2.0.4 在一次测试中发现使用dbms_xplan.display_cu ...
- dbms_xplan的display查看执行计划
DBMS_XPLAN包包括一系列函数,主要是用于显示SQL语句的执行计划,且不同的情形下使用不同的函数来显示,如预估的执行计划则使用 display函数,而实际的执行计划则是用display_curs ...
随机推荐
- CLI结果输出
例子:FTP::11.245.253.20_CIPS_dev_bak\/opt/IBM/db2/V9.7/samples/ 要不要修改整体结构,先看看细节 CLI结果输出: 1. 逐条的获取--确定产 ...
- gitignre
1.配置语法: 以斜杠“/”开头表示目录: 以星号“*”通配多个字符: 以问号“?”通配单个字符 以方括号“[]”包含单个字符的匹配列表: 以叹号“!”表示不忽略(跟踪)匹配到的文件或目录: PLAC ...
- 关于linux下零散的东西 --慢慢补充
一.截图 ,使用Shift+Ctrl+PrtSc就可以截图. 二.tar命令参数 c:表示压缩 x:表示解压 z:表示gzip的方式解/压缩 j:表示bzip2的方式解/压缩 三.串口终端ke ...
- 【Android】Android SDK在线更新镜像服务器
Android SDK在线更新镜像服务器 中国科学院开源协会镜像站地址: IPV4/IPV6: http://mirrors.opencas.cn 端口:80 IPV4/IPV6: http://mi ...
- input获取永久焦点
$(function () { $('#test').blur(function () { var that = this; //或者用闭包 setTimeout(function () { $(th ...
- Angular之【form提交问题】
前端页面是这样: <form class="form-horizontal" role="form" name="LoginForm" ...
- WPF自定义控件之带倒计时的按钮--Button
1.说明 之前做过一个小项目,点击按钮,按钮进入倒计时无效状态,计时完成后,恢复原样,现在就实现该效果---带倒计时的按钮 2.效果 1)正常状态 2)MouseOver( ...
- 1036. Boys vs Girls (25)
#include <stdio.h>#include <string.h>int main(){ int n,i; while(scanf("%d",&am ...
- 2016 Multi-University Training Contest 1 Necklace 环排+二分匹配
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5727 题意:由2*N颗宝石构成的环(阴阳宝石均为N颗且标号均从1~N) 之后给定M组 a,b;表示阳宝石a ...
- ThinkPHP的缓存 F方法
一般使用文件方式的缓存就能够满足要求,而thinkphp还提供了一个专门用于文件方式的快速缓存方法f方法. 由于采用的是php返回方式,所以其效率较s方法较高. f方法具有如下特点: 1.简单数据缓存 ...