当前位置: 首页 > 科技观察

必看干货-Oracle常见等待事件说明(上)

时间:2023-03-17 00:22:22 科技观察

1.Bufferbusywaits这种等待事件的产生本质上只是说明一个session正在等待一个Buffer(数据块),但是造成这种现象的原因有很多。两种常见的是:--当一个会话视图修改了一个数据块,但是这个数据块正在被另一个会话修改。--当一个session需要读取一个数据块,但是这个数据块正在被另一个session读入内存。在新版本中,第二种情况已经被隔离,取而代之的是其他session读取~Bufferbusywaits等待事件常见于数据库中的热队列,当多个用户频繁读取或修改同一个数据时会产生这种等待事件块被加载。如果等待时间较长,我们可以在AWR或statspack报告中看到。此等待事件具有三个参数。要查看有多少个参数,我们可以使用以下SQL:SQL>selectname,parameter1,parameter2,parameter3fromv$event_namewherename='bufferbusywaits';NAMEPARAMETER1PARAMETER2PARAMETER3-------------------------------------------------bufferbusywaitsfile#block#class#2。数据块在Bufferlatchmemory中的存储位置被记录在一个哈希表(cachebufferchains)中。当一个会话需要访问一个数据块时,它首先搜索哈希列表,从列表中获取数据块的地址,然后使用这个地址访问所需的数据块。这个列表Oracle将使用一个锁存器来保护它的完整性。当一个会话需要访问这个链表时,它需要获得一个Latch。只有这样才能保证在本次会话浏览过程中列表不会发生变化。bufferlatch等待事件的主要原因是Bufferchains太长,导致session查找链表的时间过长,导致其他session处于等待状态。同一个数据块被频繁访问,也就是我们通常所说的热点问题。这个等待事件有两个参数:latchaddr:会话申请的latch在SGA中的虚拟地址。可以根据这个地址通过如下SQL语句找到对应的Latch名称:select*fromv$latcha,v$latchnamebwhereaddr=latchaddranda.latch#=b.latch#;chain#:缓冲区链哈希列表中的索引值。当该参数的值等于s0xfffffff时,表示当前会话正在等待一个LRUlatch。3、控制文件并行写入当数据库中有多个控制文件副本时,Oracle需要保证信息同步写入到各个控制文件中。这是一个并行的物理操作过程,因为它被称为控制文件的并行写入。在这样的操作过程中,会产生一个控制文件并行写等待事件。控制文件频繁写入的原因有很多,例如:--日志切换过于频繁,导致相应的控制文件信息频繁更新。--系统I/O出现瓶颈,导致所有I/O等待。这个等待事件包含三个参数:--Files:Oracle要写入的控制文件的数量。--Blocks:写入控制文件的数据块数。--requests:写入控制的I/O请求数。4.控制文件顺序读当数据库需要读取控制文件上的信息时,就会发生这个等待事件,因为控制文件的信息是顺序写入的,所以也是顺序读取的,所以称为控制文件顺序read,经常出现在以下几种情况:--备份控制文件--RAC环境下不同实例之间控制文件的信息共享--读取控制文件的头信息--读取控制文件的其他信息等待事件有3个参数:--File#:要从中读取信息的控制文件的文件号。--Block#:读取控制文件信息的起始数据块号。--Blocks:需要读取的控制文件数据块的数量。5.dbfileparallelread这是一个非常具有误导性的等待事件。其实这个等待事件和并行操作(比如并行查询,并行DML)无关。还原数据库时会发生此事件。当一些数据块需要恢复时,Oracle会从数据文件中并行读取到内存中进行恢复操作。这个等待事件包含三个参数:--Files:操作需要读取的文件数。--Blocks:操作需要读取的数据块数。--requests:操作需要执行的I/O次数。6.dbfileparallelwrite这是一个后台等待事件。也与用户的并行操作无关。它由后台进程DBWR生成。当后台进程DBWR要向磁盘写入脏数据时,就会出现这种等待。DBWR会将脏数据批量并行写入磁盘上相应的数据文件中。在批处理作业完成之前,DBWR会有这个等待事件。如果只是这个等待事件,对用户的操作影响不大。当有freebufferwaits等待事件时,说明此时内存中的可用空间不足,此时会影响用户的操作,比如影响用户将脏数据块读入内存。当发生dbfileparallelwrite等待事件时,可以通过开启操作系统的异步I/O来缓解等待。当使用异步I/O时,DBWR不再需要等到所有数据块都写入磁盘,只需要等到数据写入到一定百分比,再进行后续操作。这个等待事件有两个参数:--Requests:操作需要执行的I/O次数。--Timeouts:等待的超时时间。7、Db文件散读的等待事件在实际生产数据库中经常可以看到。这是一个用户操作引起的等待事件。当用户发出需要为每个I/O读取多个数据块的SQL操作时,就会产生这个等待事件。最常见的两种情况是全表扫描(FTS:FullTableScan)和索引快速扫描(IFFS:indexfastfullscan)。这个名字中的分散(divergence)可能会让很多人认为它是分散读取数据块的,但实际上恰恰相反,当发生这样的等待事件时,SQL操作是顺序读取数据块的,比如FTS或者IFFS(如果要读取的数据块已经存在于内存中则忽略)。这里的散是指读取到的数据块在内存中的存储方式。它们被读入内存后,是分散存在于内存中的,而不是连续存在的。这个等待事件有三个参数:--File#:要读取的数据块所在数据文件的文件号。--Block#:要读取的起始数据块号。--Blocks:读取的数据块数。8.Dbfilesequentialread的等待事件在实际生产数据库中也很常见。当Oracle每次I/O只需要读取单个数据块时,就会产生这个等待事件。最常见的情况是索引访问(IFFS除外)、回滚操作、以ROWID形式访问表中的数据、重建控制文件、对文件头做DUMP等。这里的顺序不是指Oracle访问数据以顺序的方式。像dbfilescatteredread,是指读取的数据块在内存中是连续存储的。这个等待事件有三个参数:--File#:要读取的数据块的文件号在数据文件中被锁定。--Block#:要读取的起始数据块号。--Blocks:要读取的数据块数(这里应该等于1)。9.dbfilesinglewrite这种等待事件通常只发生在一种情况下,即Oracle更新数据文件的头信息时(如Checkpoint)。当这种等待事件比较明显时,需要考虑是不是数据库中的数据文件数量过多,导致Oracle更新所有文件头(checkpoint)的时间过长。这个等待事件有三个参数:--File#:待更新数据块所在数据文件的文件号。--Block#:需要更新的数据块号。--Blocks:需要更新的数据块数(通常应该等于1)。10、直接路径读当会话直接将数据块读入PGA而不是SGA时,会发生该等待事件。这些读取的数据通常是会话的私有数据,所以不需要作为共享数据放在SGA中,因为这样做没有意义。这些数据通常来自临时段上的数据,比如SQL在一个session中的排序数据,并行执行中间产生的数据,HashJoin和mergejoin产生的排序数据,因为这些数据只是对于当前session的SQL操作是有意义的,所以不需要放在SGA中。当直接路径读等待事件发生时,意味着磁盘上产生了大量的临时数据,如排序、并行执行等操作。或者这意味着PGA中没有足够的可用空间。该等待事件具有三个参数:--描述符地址:指向当前会话正在等待的直接读取I/O的指针。--firstdba:描述符地址中最早的I/O数据块地址。--Blockcnt:描述符地址上下文中涉及的有效缓冲区数。11.直接路径写这个等待事件正好和直接路径读相反。就是会话不经过SGA,直接从PGA向磁盘文件写入一些数据。这种情况通常发生在:--使用临时表空间排序(内存不足)--直接加载数据(使用append方法加载数据)--并行DML操作。这个等待事件有三个参数:--描述符地址:指向当前会话正在等待的直接I/O的指针。--firstdba:描述符地址中最早的I/O数据块地址。--Blockcnt:描述符地址上下文中涉及的有效缓冲区数。12.EnqueueEnqueue这个词其实是对锁的另一种描述。当我们在AWR报告中发现longenqueuewaiting事件时,说明数据库中存在阻塞和等待,我们可以关联AWR报告中的enqueueactivity部分来判断是哪种锁在长时间等待。此等待事件有2个参数:--Name:入队的名称和类型。--Mode:入队模式。13.空闲缓冲区等待当一个会话从磁盘读取数据块到内存中时,它需要在内存中找到空闲的内存空间来存储这些数据块。当内存中没有空闲空间时,就会发生这种等待;另外还有一种情况,会话在做一致性读的时候,需要在某个时刻构造一个数据块的原像(image)。这时候就需要申请内存来存放这些新构造的数据块。当找不到这样的内存块时,也会发生此等待事件。当数据库中出现严重的freebufferwaits等待事件时,可能的原因有:--数据缓冲区太小,导致空闲空间不足--内存中脏数据太多,DBWR无法写入这些脏数据数据及时写入磁盘为了释放空间,这个等待事件包含2个参数:--File#:要读取的数据块所在数据文件的文件号。--Block#:要读取的数据块的块号。--查询拦截的语句:SELECT/*+ORDEREDUSE_HASH(H,R)*/h.sidhold_sid,holds.usernameh_user,holds.lockwaith_lockwait,holds.statush_status,holds.moduleh_module,holds.row_wait_obj#h_obj,holds.row_wait_row#h_row,r.sidwait_sid,waits.usernamew_user,waits.lockwaitw_lockwait,waits.statusw_status,waits.modulew_module,waits.row_wait_obj#w_obj,waits.row_wait_row#w_row,h.typeh_type,h.id1h_id1,h.id2h_id2,h.lmodeh_lmode,h.requesth_request,h.ctimeh_ctime,h.blockh_block,r.typer_type,r.id1r_id1,r.id2r_id2,r.lmoder_lmode,r.requestr_request,r.ctimer_ctime,r.blockr_block,'altersystemkillsession'''||holds.sid||','||holds.serial#||''';--kill-9'||nvl(holdp.spid,'null')killhold,holdsql.sql_texthsql,waitsql.sql_textwsqlFROMv$lockh,v$lockr,v$sessionholds,v$sessionwaits,v$processholdp,v$sqlareaholdsql,v$sqlareawaitsqlWHEREh.BLOCK=1ANDr.BLOCK=0ANDh.TYPE<>'MR'ANDr.TYPE<>'MR'ANDh.id1=r.id1ANDh。id2=r.id2ANDh.sid=holds.sidANDr.sid=waits.sidANDholds.paddr=holdp.addr(+)ANDholds.sql_address=holdsql.address(+)ANDholds.sql_hash_value=holdsql.hash_value(+)ANDwaits.sql_address=waitsql.address(+)ANDwaits.sql_hash_value=waitsql.hash_value(+);14.Latchfree在10g之前的版本中,latchfree等待事件代表所有的latch等待。10g之后,隔离了一些常用的latch事件:这个等待事件有3个参数:--Address:会话等待的latch的地址--Number:latch编号,通过这个编号,可以找到这个latch的相关信息来自v$latchname视图。15.Librarycachelock这个等待时间出现在不同用户由于对同一个数据库对象的并发操作而共享资源时。比如一个用户在对一张表进行DDL操作的时候,如果其他用户要访问这张表,就会有librarycachelockwaiting事件,必须等到DDL操作完成后才能继续操作。该事件包含四个参数:--句柄地址:加载对象的地址。--锁地址:锁的地址。--Mode:加载对象的数据片段。--Namespace:加载对象在v$db_object_cache视图中的命名空间名称。