oracle学习篇:八、等待事件

冷暖自知 提交于 2019-12-03 22:44:40

当一个进程连接到数据库之后,进程所经历的种种等待就开始被记录,并且通过一系列的动态性能视图进行展现。通过等待事件用户可以很快地发现数据库的性能瓶颈,从而进行针对性能的优化和分析。

8.1 等待事件的源起

查询数据库版本:

select * from v$version;

查询等待事件数量:

select * from v$event_name;

oracle的等待事件,主要可以分为两类,即空闲idle等待事件和非空闲non-idle等待事件。空闲等待事件指oracle正等待某种工作,在诊断和优化数据库的时候,不用过多注意这部分事件。非空闲等待事件专门针对oracle的活动,指数据库任务或应用运行过程中发生的等待,这些等待事件是,在调整数据库的时候应该关注和研究的。

查询空闲等待事件:

select * from v$event_name where name like '%idle%';

也可以通过查询v$system_wait_class视图获得各类主要等待事件的等待时间和等待次数等信息。

select * from v$system_wait_class;

8.2 从等待发现瓶颈

v$session视图:记录数据库当前连接的session信息,和session的生命周期相关,并不记录历史信息;

v$session_wait视图:记录当前数据库连接的活动session正在等待的资源或事件信息;

v$system_event视图:记录数据库自启动以来所有等待事件的汇总信息,用户可以迅速地获得数据库运行的总体概况。

8.2.1 v$session和v$session_wait

对于不同的event,具体参数表示的含义也不相同,p1、p2、p3,用户可以通过v$event_name视图来查看这些参数的定义。

8.2.2 从v$sqltext中追踪

业务及开发人员报告系统运行缓慢,已经影响业务系统正常使用,请求协助诊断。

数据库运行缓慢,可以判断数据库可能经历了等待,那么可以通过v$session_wait视图来入手。查询v$session_wait获取各进程等待事件。

select sid,event,p1,p1text from v$session_wait;

对于本案例,发现大量的db_file_scattered_read及db_file_sequential_read等待,并且全表扫描的等待都位于文件号为17的数据文件上。显然全表扫描等操作成为系统最严重的性能影响因素。

db_file_scattered_read(DB文件分散读取)这种情况通常显示与全表扫描相关的等待。当数据库基于全表扫描时,基于性能的考虑,数据会分散读入buffer cache。如果这个等待事件比较显著,可能说明对于某些全表扫描的表,没有创建索引或者没有创建合适的索引,可能需要检查这些数据表以确定是否进行了正确的设置。

然而这个等待事件不一定意味着性能低下,在某些条件下oracle会主动使用全表扫描来替换索引扫描以提高性能,这和访问的数据量有关,在cbo下oracle会进行更为只能的选择,在rbo下oracle更倾向于使用索引。

8.2.3 捕获相关sql

确定这些进程因为数据访问产生了等待,考虑捕捉这些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 asc;

set autotrace trace explain;

 通过任务计划,发现大量全表扫描,查询sql语句,优化索引。

8.3 oracle的增强

8.3.1 新增v$session_wait_history视图

8.3.2 ASH新特性

8.3.3 自动负载信息库AWR的引入

内存中记录的ASH信息始终是有限的,为了保留历史数据,这些信息最终需要写入磁盘。AWR收集关于该特定数据库的操作统计信息和其他统计信息,oracle以固定的时间间隔(默认为每小时一次)为其所有重要统计信息和负载信息执行一次快照,并将这些快照存储在AWR中。这些信息在AWR中保留给定的时间(默认为一周),然后被清除。

 AWR的采用工作由后台进程MMON每60分钟执行一次。

AWR的行为受到数据库的另外一个重要初始化参数statistics_level影响,该参数有三个可选值:

①BASIC:AWR的统计信息收集和所有自我调整的特性都被关闭;

②TYPICAL:数据库收集部分统计信息,这些信息为典型的数据库监控需要,是数据库的缺省设置;

③ALL:所有可能的统计信息都被收集。

总结:

(1)v$session:代表数据库活动的开始,视为源起;

(2)v$session_wait:用以实时记录活动session的等待情况,是当前信息;

(3)v$session_wait_history:是对v$session_wait的简单增强,记录活动session的最近10次等待;

(4)v$active_session_history:是ASH的核心,用以记录活动session的历史等待信息,每秒采样一次,这部分内容记录在内存中,期望值是一个小时的内容;

(5)wrh$_active_session_history:是v$sctive_session_history在AWR的存储地,v$sctive_session_history中记录的信息会被定期(每小时一次)的刷新到负载库中,并缺省保留一个星期用于分析;

(6)dba_hist_active_sess_history视图是wrh$_active_session_history视图和其他几个视图的联合展现,通常通过这个视图进行历史数据的访问。

 8.3.4 自动数据库诊断监控ADDM的引入

通过ADDM,oracle试图使数据库的维护、管理和优化工作变得更加自动和简单。

ADDM可以定期检查数据库的状态,根据内建的专家系统,自动确定潜在的数据库性能瓶颈,并提供调整措施和建议。

8.4 顶级等待事件

v$system_event,该视图记录的是数据库自启动以来等待事件的汇总,通过查询该视图,可以快速获得数据库等待事件的总体概况,了解数据库运行的基本状态。

8.5 重要等待事件

8.5.1 db file sequential read(数据文件顺序读取)

db file sequential read是个非常常见的I/O相关的等待事件,通常显示与单个数据块相关的读取操作,在大多数情况下,读取一个索引块或者通过索引读取一个数据块时,都会记录这个等待。

这个等待有三个参数p1,p2,p3,其中p1代表oracle要读取的文件的绝对文件号,p2代表oracle从这个文件中开始读取的起始数据块块号,p3代表读取的block数量通常这个值为1,表名是单个block被读取。

select name,wait_class,parameter1,parameter2,parameter3 from v$system_event where name='db file sequential read';

 

 这个等待事件被归入User I/O一类。

如果这个等待事件比较显著,可能表示在多表连接中,表的连接顺序存在问题,可能没有正确的使用驱动表;或者可能索引的使用存在问题,并非索引总是最好的选择。

在大多数情况下,通过索引可以更为快速的获取记录,所以对于一个编码规范、调整良好的数据库,这个等待事件很大通常是正常的。

但是在很多情况下,使用索引并不是最佳的选择,比如读取较大表中大量的数据,全表扫描可能会明显快于索引扫描,所以在开发中就应该注意,对于这样的查询应该进行避免使用索引扫描。

oracle引入了段级统计信息收集的新特性,可以通过查询v$segment_statistics视图,找出物理读显著的索引段或者是表段,研究其数据结构,看能否通过重建或重新规划分区、存储参数等手段降低其I/O访问。

select * from v$segstat_name;

对于CBO模式下的数据库,应当及时收集统计信息,使SQL可以选择正确的执行计划,避免因为统计信息陈旧而导致的执行错误等。

8.5.2 db file scattered read(数据文件离散读取)

从v$event_name视图可以看到,该事件有3个参数,分别代表文件号、起始数据块号、数据块的数量:

select  * from v$event_name where name='db file scattered read';

起始数据块号加上数据块的数量,这就意味着oracle session正在等待多块连续读操作的完成。这个操作可能与全表扫描(full table scan)或者快速全索引扫描(INdexes fast full scan)的连续读取相关。根据经验,通常大量的db file scattered read等待可能意味着应用问题或索引缺失。

在实际环境的诊断过程中,可以通过v$session_wait视图发现session的等待,再结合其他视图找到存在问题的SQL等根本原因,从而从根本上解决问题。当这个等待事件比较显著时,也可以结合v$session_longops动态性能视图来进行诊断,该视图中记录了长时间(运行事件超过6秒的)运行的事务,可能很多是全表扫描操作(不管怎样,这部分信息都是值得注意的)。

oracle新增了一个视图v$sql_plan用于记录当前系统Library cache中SQL语句的执行计划,可以通过这个视图找到存在问题的sql语句。

8.5.3 direct path read/write(直接路径读/写)

直接路径读通常发生在oracle直接读数据到PGA时,这个读取不需要经过SGA。直接路径读等待事件的3个参数分别是:file、first block和block的数量,这个等待事件被归于User I/O一类。

这类读取通常在一下情况被使用:

磁盘排序IO操作;

并行查询从属进程;

预读操作。

最为常见的是第一种情况,在DSS系统中,存在大量的Direct path read是很正常的,但是在OTLP系统中,,通常显著的直接路径读都意味着系统应用存在问题,从而导致大量的磁盘排序读取操作。

 直接路径写通常发生在oracle直接从PGA写数据到数据文件或临时文件,这个写操作可以绕过SGA。直接路径写等待事件的3个参数分别是:file#,first block和block数量,被归于User I/O一类。

这类写入操作通常在以下情况被使用:

直接路径加载;

并行DML操作;

磁盘排序;

对未缓存的“LOB”段的写入,随后会记录为direct path write(lob)等待;

最为常见的直接路径写,多数因为磁盘排序导致。对于这一写入等待,应该找到I/O操作最为频繁的数据文件(如果有过多的排序操作,很有可能就是临时文件),分散负载,加快其写入操作。

如果系统存在过多的磁盘排序,会导致临时表空间操作频繁,对于这种情况,可以考虑为不同用户分配不同的临时表空间,使用多个临时表空间,写入不同磁盘或者裸设备,从而降低竞争,提高性能;应该考虑使用本地管理local的临时表空间,而不是字典dictionary管理。

从dba_tablespaces视图可以获得这部分信息。

内存排序率=sort-momory/(sort-disk+sort-memory)

对于显著的磁盘排序,可以很容易地猜想到,临时表空间的读写操作肯定相当频繁。

8.5.4 日志文件相关等待

select * from v$event_name where name like "%log%";

(1)log file switch(日志文件切换)

log file switch当日志文件发生切换时出现,在数据库进行日志切换时,LGWR需要关闭当前日志组,切换并打开下一个日志组,在这个切换过程中,数据库的所有DML操作都处于停顿状态,直至这个切换完成。

log file switch主要包含两个子事件。

①log file switch(archived needed),即日志切换(需要归档)

这个等待事件出现时通常是因为日志组循环写满以后,在需要覆盖先前日志时,发现日志归档未完成,出现该等待。由于redo不能写出,该等待出项时,数据库将陷入停顿状态。

出现该等待,可能表示I/O出现问题、归档进程写出缓慢,也有可能是日志组设置不合理等原因导致。针对不同原因,可以考虑采用的解决办法有:

可以考虑增大日志文件和增加日志组;

移动归档文件到快速磁盘;

调整log_archive_max_processed参数等。

② log file switch(checkpoint imcomplete),即日志切换(检查点未完成)

当所有的日志组都写满之后,LGWR视图覆盖某个日志文件,如果这时数据库没有完成写出由这个日志文件所保护的脏数据时(检查点未完成),该等待事件出现,数据库同样将陷于停顿状态。

该事件通常表示DBWN写出速度太慢或者I/O存在问题,未解决该问题,可能需要考虑增加额外的DBWN或者增加日志组或日志文件大小。

log file switch引起的等待都是非常重要的,如果出现就应该引起重视,并由DBA介入进行及时处理。

(2)log file sync(日志文件同步)

当一个用户提交或回滚数据时,LGWR将会话期的重做日志由日志缓冲区写入到重做日志中,LGWR完成任务以后会通知用户进程。日志文件同步过程必须等待这一过程成功完成。对于回滚操作,该事件记录从用户发出rollback命令到回滚完成的时间。

如果该等待过多,说明LGWR的写出效率低下,或者系统提交过于频繁。针对该问题,可以通过log file parallel write等待事件或user commits、user rollback等统计信息来观察提交或回滚次数。

可能的解决方案主要有:

提高LGWR性能,尽量使用快速磁盘,不要把redo log file存放在raid5的磁盘上;

使用批量提交;

适当使用nologging/unrecoverable等选项。

可以通过如下公式计算平均redo写大小:

avg.redo write size=redo block written/redo writes *512 bytes

如果系统产生的redo 很多,而每次写的较少,一般说明LGWR被过于频繁的激活了。了能导致过多的redo相关Latch的竞争,而且oracle可能无法有效地使用piggyback的功能。

(3)log file single write

该事件仅与日志文件头块相关,通常发生在增加新的组成员和增进序列号时。头块写单个进行,因为头快的部分信息是文件号,每个文件不同。更新日志文件头这个操作在后台完成,一般很少出现等待,无需太多关注。

(4)log file parallel write

从log buffer写redo记录到日志文件,主要指常规写操作(相对于log file sync)。如果log group 存在多个组成员,当flush log buffer时,写操作是并行的,这时候此等待事件可能出现。

尽管这个写操作并行处理,直到所有I/O操作完成该写操作才会完成(如果磁盘支持异步I/O或者使用IO SLAVE,那么即使只有一个redo log file member,也有可能出现此等待)。这个参数和log file sync时间相比较,可以用来衡量log file的写入成本,通常称为同步成本率。

(5)log buffer space(日志缓冲区间)

当数据库产生日志的速度比LGWR的写出速度快,或者是当日志切换太慢时,就会发生这种等待。这个等待出现时,通常表明redo log buffer过小,为解决这个问题,可以考虑增大日志文件的大小,或者增加日志缓冲器的大小。

另外一个可能的原因是磁盘I/O存在瓶颈,可以考虑使用写入速度更快的磁盘。在允许的条件下设置,可以考虑使用裸设备来存放日志文件,提高写入效率。在一般的系统中,最低的标准是,不要把日志文件和数据文件放在一起,因为通常日志文件只写不读,分离存放可以获得性能提升,尽量使用raid10而不是raid5磁盘来存储日志文件。

8.5.6 Latch Free(闩锁释放)

Latch Free通常被称为闩锁等待,这个名称常常引起误解,实际上应该在前面加上一个wait,当数据库出现这个等待时,说明有进程正在等待某个Latch被释放,也就是waiting Latch Free。

Latch是一种低级排队(串行)机制,用于保护SGA中共享内存结构。Latch就像是一种快速的被获取和释放的内存锁,用于防止共享内存结构被多个用户同时访问。

其实不必把Latch想得过于复杂,Latch通常是操作系统是利用内存中的某个位置,通过设置变量0或非0,来表示Latch是否已经被取得,大多数的操作系统,是使用test and set的方式来完成latch持有检查或持有的。

(1)Latch的分类

select * from v$latch;

分为两类:willing-to-wait和immediate

willing-to-wait:是指如果所请求的latch不能立即得到,请求进程将等待一段很短的时间后再次发出请求。进程一直重复此过程直到得到latch。

immdiate:是指如果所请求的latch不能立即得到,请求进程就不再等待,而是继续执行下去。

在v$latch中的以下字段记录了willing-to-wait请求:

gets:

misses:

sleeps:

在v$latch中的以下字段记录immedaite类请求:

immediate_gets

immediate_misses

oracle的latch机制是竞争,其处理似于网络里的csma/cd,所有用户进程争夺latch,对于愿意等待类型的latch,如果一个进程在第一次尝试中没有获得latch,那么它会等待并且再次尝试,如果系统存在多个CPU,那么此过程将围绕该latch开始自旋spin,如果经过_spin_count次争夺不能获得latch,然后该进程转入睡眠状态,持续一段指定长度的时间,然后再次醒来,按顺序重复之前的操作。

(sleep引起上下文切换,latch竞争是非常昂贵的,可能导致严重的CPU耗用)

需要注意的是,immediate类型的latch通常是因为存在多个可用latch,最常见的如redo copy latch,当process想要取得redo copy latch时,它首先要求其中一个latch,如果可以取得就持有该latch,如果不能获取,它会立即转向要求另一个redo copy latch,只有所有的redo copy latch都无法取得时,才会sleep与wait。

immediate的另外一种原因是每个latch都有evel的概念(level1-14),当一个process需要取得一组latches时,为避免死锁,取得latches有一定的顺序,即process新请求的latch的level,应该大于process目前所握有的latch的level。所以如果process要求的新latch的level小于目前所持有的latch的level,正常情况下,oracle要求process先释放目前所持有的所有latch,再依次取得这些latch。为节省时间,oracle允许进程以nowait方式要求较低level的lath,如果成功取得,既可以避免deadlock又可以节省时间。

(2)redo copy latch

 下面以redo copy latch为例简要说明一下immediate类型及latch的处理。

一个进程在修改数据时产生redo,redo首先在PGA中保存,当进程需要将redo信息copy进入redo log buffer时,需要获得redo copy latch,获得了该latch以后才能把redo拷贝到log buffer中。redo copy latch表明进程正在把redo拷贝入log buffer中,在此过程中,LGWR应该等待直到进程拷贝完成才能把目标log buffer block写入磁盘。

redo copy latch获取以后,进程紧接着需要获取redo allocation latch,分配redo空间,空间分配完成以后,redo allocation latch即被释放,进程把PGA里临时存放的redo信息copy 入redo log buffer,copy完成以后,redo copy latch释放。

在完成redo copy以后,process可能需要通知LGWR去执行写出(如果redo copy是commit等因素触发的)。

为了避免LGWR被不必要的Post,进程需要先获取redo writing latch去检查LGWR是否已经激活或者已经被Post。如果LGWR已经激活或被Post,redo writing latch将被释放。如果redo writing latch竞争过多,可能意味着用户的提交过于频繁。通过系统统计信息可以获得这些信息。

在执行redo copy的过程中,进程以log file sync事件处于等待。当进程从log file sync中等待醒来以后,进程需要重新获得redo allocation latch来检查是否相应的redo已经被写入redo log file,如果尚未写入,进程必须继续等待。

(3)redo allocation latch

当进程需要向redo log buffer写入redo信息时需要获得此latch,分配redo log buffer空间。所以,如果对于一个繁忙的数据库系统,该latch通常也是竞争激烈的latch之一。

(4)latch的增强

最常见的latch集中于buffer cache的竞争和shared pool的竞争。与buffer cache相关的主要latch竞争有cache buffers chain和cache buffers LRU chain,与shared pool相关的主要latch竞争有shared pool latch和library cache latch等。

buffer cache的latch竞争经常是由于热点块竞争引起,shared pool的latch竞争通常是由于sql的大量硬解析引起。

第八章完 

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