9.1 使用autotrace功能辅助sql优化
oracle sql*plus提供一个autotrace的功能,可以用于跟踪sql的执行计划,收集统计信息,通常被作为sql的优化工具之一而被广泛使用。
9.1.1 autotrace功能的启用
autotrace有几个常用选项,简单说明如下:
set autotrace off:不生产autotrace报告,这是缺省模式;
aet autotrace on explain:autotrace只显示优化器执行路径报告;
set autotrace on statistics:只显示执行统计信息;
set autotrace on:包含执行计划和统计信息;
set autotrace traceonly:同set autotrace on,但是不显示查询输出。
9.1.2 autotrace功能的增强
9.1.3 autotrace功能的内部操作
当使用autotrace功能时,在数据库内部,oracle实际上是启动了2个session连接,一个session用于执行查询等操作,另外一个session用于记录执行计划和输出最终结果等操作。
这两个session都是由一个进程衍生。select * from v$process;一个进程在数据库中可能对应多个session。
主要的操作步骤如下:
(1)执行计划的输出
(2)统计信息输出
9.1.4 使用autotrace功能辅助sql优化
9.2 捕获问题SQL解决过度CPU消耗问题
在生产环境中,可能会经常遇到CPU过度使用而影响系统性能或正常运行的问题。大多数情况下,系统的性能问题都是有不良SQL代码引起的。
问题描述:业务及开发人员报告系统运行缓慢,已经影响业务系统正常使用使用,请求协助诊断。
9.2.1 使用vmstat检查系统当前情况
首先登陆数据库主机,检查当前系统状况。使用vmstat检查,发现CPU资源已经耗尽,大量任务位于运行队列:
vmstat 3
对于vmstat的用法及输出,简要说明一下。vmstat是unix平台上一个常用的工具,可以帮助用户查看系统内存及CPU使用情况。
vmstat最常用的两个参数是t[n],t表示采样间隔,n表示采样次数。
对于前3列的procs输出,分别代表以下含义。
r:指运行队列中的进程数,如果这个参数经常超过CPU数量可能说明CPU存在瓶颈。
b:IO被block的进程数。
w:idle的被SWAP的进程数。
最后一项cpu标识cpu资源的分配和使用情况,最后一列idle通常被用来衡量cou的空闲情况。
9.2.2 使用top工具辅助诊断
通过top工具,可以查看进程cpu耗用情况,如果存在进程异常,可以通过top定位,为进一步诊断提供依据。
从top的输出中可以发现有大量进程处于running的运行状态,cpu消耗很平均,单进程消耗大约在1%左右,基本可以排除个别进程异常导致cpu问题的可能。
9.2.3 检查进程数量
对于一个生产数据库系统,稳定运行的进程数量通常是可知的。
ps -ef|grep ora|wc -l
发现此时系统存在大量的oracle进程,大约在300左右,大量进程消耗了几乎所有cpu资源,而正常情况下oracle连接数应该在100左右。
9.2.4 登陆数据库
判断数据库可能经历了等待,那么oracle数据库提供了相关视图供用户查询和发现问题,v$session_wait是首先值得关注的。查询v$session_wait获取各进程等待事件。
select sid,event,p1,p1text from v$session_wait;
对于本案例,发现存在大量dbfile scattered read及db file sequential read等待。显然全表扫描等操作成为系统最严重的的性能影响因素。
9.2.5 捕获相关SQL
select sql_text from v$sqltext a where a.hash_value =(select sql_hash_value from v$session b where b.sid='&sid') order by piece ;
使用该语句,通过从v$session_wait中获得的等待全表扫描或索引扫描的进程sid,可以捕获可能存在问题的sql语句。
使用该应用用户连接,通过autotrace功能加成以上sql的执行计划。
select name,value from v$sysstat where name in ('table scans (short tables)','table scans (long tables)');
其中table scans(short tables)指对于小表的全表扫描的次数;table scan(long tabels)指对于大表的全表扫描的次数。
所以要区分大小表是因为全表扫描可能引起buffer cache的抖动,缺省情况下,大表的全表扫描会被置于LRU的末端,以期尽快老化,减少buffer的占用。oracle的多缓冲池管理技术给了我们另外一个选择,对于不同大小7不同使用频率的数据表,从建表之初就可以指定其存储buffer,以使得内存使用非常有效。
9.2.6 创建新的索引以消除全表扫描
检查发现在某某字段上并没有索引,而该字段具有很好的区分度,考虑在该字段创建索引以消除全表扫描。
9.2.7 观察系统状况
原大量等待消失,CPU使用正常,问题解决。
9.2.8 性能何以提高
有效地降低SQL的逻辑读是SQL优化的基本原则之一。
9.2.9 小结
通常开发人员很少注意SQL代码的效率,一条低效的sql语句就可能毁掉整个数据库。
9.3 使用SQL_TRACE/10046事件进行数据库诊断
该事件是oracle提供的用于进行SQL跟踪的手段,是强有力的辅助诊断工具。在日常的数据库问题诊断和解决中,SQL_TRACE是非常常用的方法。当在数据库中启动SQL_TRACE或者设置10046事件之后,oracle将会启动内核跟踪程序,持续记录回话的相关信息,并写入到相应的trace文件中。跟踪记录的内容包括sql的解决过程、sql的执行计划、绑定变量的使用及会话中发生的等待事件等。
9.3.1 SQL_TRACE及10046事件的基础介绍
(1)SQL_TRACE说明
SQL_TRACE的取值可以启用或禁用SQL TRACE工具,设置SQL_TRACE为true可以收集用于性能优化或问题诊断;DBMS_SYSTEM包也可以用来实现同样的功能。
参数类型——布尔型
缺省值——false
参数类别——静态
取值范围——true|false
设置初始化参数SQL_TRACE为true会对整个实例产生严重的性能影响,所以在产品环境中如非必要,确保不要设置这个参数。如果只是对特定的session启用跟踪,可以使用alter session或dbms_system.sql_trace_in_session来设置。如果必须在数据库级启动sql_trace,则需要保证以下条件以最小化性能影响。
至少保证有25%的cpu idle;
为user_dump_dest分配足够的表空间;
条带华磁盘以减轻IO负担。
在使用SQL_TRACE之前,几个注意事项需要简要说明一下:
初始化参数timed_statistics,最好设置为true,否则一些重要信息不会被收集;
设置max_dump_file_size,改参数跟踪文件的大小限制,可以以操作系统块为单位设置,也可以以KB或MB为单位设置;如果跟踪的信息较多,可以干脆设置为unlimited。
alter session set max_dump_file_size=unlimited;
记住前面的警告,你需要有足够的空间保存trace文件,跟踪过程产生的trace文件可能远远大于你的想象。
sql_trace可以作为初始化参数或通过alter system在全局使用,也可以通过命令行方式在具体session启用。
① 在全局启用sql_trace:
在参数文件中指定sql_trace=true
在全局启用sql_trace会导致所有进程的活动被跟踪,包括后台进程及所有用户进程,这通常会导致比较严重的性能问题,所以在生产环境中要谨慎使用。
② 在当前session级设置
大多数时候使用sql_trace来跟踪当前进程,通过跟踪当前进程可以发现当前操作的后台数据库的递归活动(这在研究数据库新特性时尤其有效),用于研究sql执行及发现后台错误等。
启用:alter session set sql_trace=true;
结束:alter session set sql_trace=false;
③ 跟踪其他用户进程
在很多时候需要跟踪其他用户的进程,而不是当前用户,这可以通过oracle提供的系统包dbms_system.set_slq_trace_in_session来完成。
设置跟踪:
exec dbms_system.set_sql_trace_in_session(sid,serial#,true);
停止跟踪:
exec dbms_system.set_sql_trace_in_session(sid,serial#,false);
(2)10046事件说明
10046事件是oracle提供的内部事件,是对sql_trace的增强,可以设置以下四个级别:
level1:启用标准的SQL_TRACE功能,等价于sql_trace;
level4:等价于level1+绑定值(bind values);
level8:等价于level1+等待事件跟踪;
level12:等价于level1+level4+level8。
类似sql_trace,10046事件可以在全局设置,也可以在session级设置。
①在全局设置
在参数文件中增加
event="10046 trace name context forever,level12"
此设置对所有用户的所有进程生效,包括后台进程。
(3)对其他用户session设置
使用dbms_system.set_ev系统包设置
desc dbms_system
参数如下:
SI,SE——来自session视图
EV
LE
NM
执行跟踪:
exec dbms_system.set_ev(sid,serial#,10046,8,'username');
结束跟踪:
exec dbms_system.set_ev(sid,serial#,10046,0,'username');
(4) 读取当前session设置的参数
9.3.2 诊断案例一:隐式转换与索引失效
下面通过几个案例来看一下sql_trace在数据库诊断及优化过程中的应用。
(1)问题描述
应用是一个后台新闻发布系统,前端展现是一个大型网站,java开发应用,通过中间件连接池连接数据库
问题描述:通过链接访问新闻页极其缓慢,后台发布管理具有同样问题。通常需要几十秒才能返回。这种性能是用户不能忍受的,需要进行优化,找到问题所在。
(2)检查并跟踪数据库进程
由于发布系统是非实时系统,诊断时是晚上,基本无用户访问。选择在前台单机相关界面,同时进行后台进程跟踪。
查询v$session视图,获取进程信息:
select sid,serial#,username from v$session;
exec dbms_system.set_sql_trace_in_session(11,214,true);
exec dbms_system.set_sql_trace_in_session(16,1024,true);
此时在前台对相关界面进行刷新,等候一段时间,关闭sql_trace。
exec dbms_system.set_sql_trace_in_session(11,214,false);
exec dbms_system.set_sql_trace_in_session(16,1024,false);
(3)检查trace文件
在user_dump_dest目录下,可以找到生产的跟踪文件,然后通过oracle提供的格式化工具tkprof对trace文件进行格式化处理,检查发现以下语句是可疑的。
大量逻辑读,全表扫描。
(4)登陆数据库检查相应索引
登陆数据库,获得索引及表结构信息。发现执行的是全表扫描,索引被忽略(字符串被转成了数字进行比较)。
(5)解决方法
在参数两侧加上单引号,即可解决这个问题。
对于用单引号引起来的数字,oracle会认为是字符串,这样就消除了隐式类型转换,索引得以被正确使用。
(6)小结
在oracle开发中,应该尽量避免使用隐式的数据类型转换,因为隐式数据类型转换可能会带来索引失效问题,给系统埋下隐患。
9.3.3 诊断案例二:跟踪后台错误
(1)问题描述
很多时候,在进行数据库操作时,如drop user、drop table等,经常会遇到这样的错误,ora-00604::error occurred at recursive SQL level 1;
单从这样的提示来看,很多时候是没有丝毫用处的,也无法确定问题出在何处。
(2)drop user出现问题
这是一个生产系统,在drop user时出现以下问题:
ora-00604:error occurred ar recursive SQL level 1;
ora-00942:table or view does not exist.
关于recursive SQL错误,这里有必要做个简单的说明。
当发出一条简单的SQL命令以后,oracle数据库要在后台解析这条命令,并转换为oracle数据库的一系列后台操作。这些后台操作统称为递归操作。
比如create table这样一条简单的DDL命令,oracle数据库在后台,实际上要把这个命令转换为对obj$、tab$、col$等底层表的插入操作;对于drop table操作,则是在这些系统表中进行反向删除操作,大家同样可以通过sql_trace进行后台跟踪,进一步了解oracle数据库的后台操作。
oracle所做的工作有时可能比我们想象的要复杂的多。
(3)跟踪问题
alter session set sql_trace=true;
drop user wapcomm;
alter session set sql_trace=false;
格式化(使用tkprof工具,如tkprof aa.trc aa.txt)跟踪文件。
是一个tkporf格式化之后,oracle把错误信息首先呈现出来。可以看到ora-00942错误是由sdo_geom_metadata_table表、视图不存在,问题由此可以定位。
(4)问题定位
对于本案例,通过Metalink(http://metalink.oracle.com)可容易获得以下解释。
对于本例,为其创建一个同义词即可解决。
(5)小结
使用sql_trace可以跟踪数据库的很多后台操作,有利于发现问题的根本所在。
9.2.4 10046与等待事件
如果需要获得更多的跟踪信息,就需要用到10046事件。
(1)10046事件的使用
alter session set events '10046 trace name context forever,level 12';
(2)10046与db_file_multiblock_read_count
这个参数代表oracle在执行全表扫描时每次IO操作可以读取的数据块的数量。本次设置为16,由于extent大小为8个block,oracle的一次IO操作不能跨越extent,所以前面的全表扫描每次只能读取8个block,进行了10次IO读取。
较大的该参数设置,可以加快全表扫描的执行,但是根据经验大于32的设置通常不会带来更大的性能提升。
alter session set events '10046 trace name context off';
(3)10046与执行计划的选择
需要注意的是,增大db_file_multiblcok_read_count参数的设置,会使全表扫描的成本降低,在cbo优化器下可能会使oracle更倾向于使用全表扫描而不是索引访问。
(4)db_file_multiblcok_read_count于系统的IO能力
db_file_multiblcok_read_count设置收到OS最大IO能力的影响,也就是说,如果系统的硬件I/O能力有限,即使设置再大的db_file_multiblcok_read_count也是没有用的。理论上最大db_file_multiblcok_read_count和系统IO能力应该有如下关系。
max(db_file_multiblcok_read_count)=maxOSIOsize/db_block_size
当然还受oracle的限制。
(5)小结
sql_trace和10046事件是oracle提供的非常强大的工具,应该深入了解,掌握并且熟练运用它。
9.4 使用物化视图进行翻页性能调整
物化视图被引入到数据库中,最初被作为数据仓库、决策支持系统的工具,是概要管理的一部分。物化视图通过预结算或汇总构建自己的独立存储,从而可以极大地提高先关处理的性能,通过查询重写功能,oralce可以自动对sql进行改写以最大程度地发挥物化视图的作用。
物化视图是典型的通过存储空间换取性能的方式,通过物化视图oracle可以:
有效地减少逻辑读取;
减少写操作——通过消除排序及聚集实现;
减少CPU的消耗——无需实时进行复杂运算;
显著提高相应速度。
9.4.1 系统环境
select * from v$version;
9.4.2 问题描述
数据库系统出现如下错误:
ora-1652:unable to extend temp segment by 128 in tablespace temp2;
临时表空间不能扩展,前台应用出现异常,研发人员请求协助,开始接入进行诊断。
9.4.3 捕获排序sql语句
首先尝试捕获引发排序的SQL语句
select /*+rule*/ distinct a.sid,a.process.a.serial# a.logon_time,a.osuser,tablespace,b.sql_text from v$session a,v$sql b,v$sort_usage c where a.sql_address=b.address(+) and a.sql_address=c.sqladdr;
发现问题:
排序是一张视图,涉及三张底层表的全表扫描,成为产生性能问题的主要原因。
9.4.5 选择解决办法
结合业务逻辑,考虑创建物化视图,通过物化视图的中间存储消除不必要的全表扫描。
必须充分考虑用户的业务需要是否允许足够的刷新时间,本次定义的是每日刷新一次。
9.4.6 进一步的调整优化
可以通过对其创建索引来进一步优化
9.4.7 小结
oralce的物化视图功能强大,使用起来也有很多需要注意的地方,最重要的是,用户的业务逻辑是否允许。
9.5 案例诊断
(1)问题描述
只要oracle开启,就会造成很高的iowait,而且执行速度非常缓慢。
(2)收集到的信息
①top结果
349个进程,346个sleep
CPU53.7%idle,18.6%user,16.9%iowait
64G real,46G free,10G swap in use,51G swap free
②sar查看oralce所在硬盘busy是99%
sar -d 2 3
③SGA显示结果
show sga;
database buffers:6828326912bytes
redo buffers:10772480bytes
④alert日志
checkpoint not complete
⑤vlog信息如下
五个日志组,4组已完成归档inactive,1个为current,大小前三组为512M,后两组为1G
⑥/etc/system相关信息
(3)通过以上信息,可以做出以下判断
①checkpoint not completed提示。说明系统I/O写出存在问题,这可能是由于数据库过于繁忙,生成日志过多,也有可能是因为存储的I/O能力存在问题。
②sar的输出。数据文件存放路径99%的I/Owait,进一步说明I/O负荷沉重,系统经历I/O等待
③v$log输出来自不同时段。在v$log输出中,多数日志处于inactive状态,所以与alert文件显然来自不同时段
(4)问题输出
提供一段连续的iostat采样信息,查看io状况;
应用可能存在问题,查询v$session_wait视图
(5)进一步信息提供
提供了iostat信息
iostat -xtcz 2 10
这个输出中,磁盘I/O繁忙度为99%时,写出能力仅有700k/s,这个IO能力是很低的
I/O能力低下是造成系统性能问题的主要原因,第一可能是硬件本身的限制,第二可能是硬件异常导致I/O能力受限。
查询v$session_wait,注意到和I/O紧密相关的等待事件这里存在:
db file scattered read意味着可能存在全表扫描,占用大量的I/O;
log file switch (checkpoint incomplete)意味着检查点完成过慢,导致日志无法切换。
(6)进一步的诊断
根本问题在于I/O,检查点不能完成说明DBWN的性能太差,写出的过慢,写出慢是因为I/O存在瓶颈。
优化全表扫描的语句,减少I/O竞争和使用。
可能存在硬件故障,导致了性能低下。
(7)最后问题的定位
确定了两个原因:
硬件出现问题;
存在大表全表扫描。
9.6 总结
加油~
本书完。