oracle学习篇:九、性能诊断与SQL优化

戏子无情 提交于 2019-12-04 00:02:16

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 总结

加油~

本书完。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!