一. 概述
我们知道,在oracle中,每修改一条数据都会生成一条重做数据(也就是redo,里面记录了修改后的内容)。目的就是为了将修改的数据备份,方便今后重做。现在有一个问题。oracle中只要修改数据,都会生成redo,这些redo会存放在一个叫做重做日志缓冲区里面。如果同时多个回话在修改数据,都要往重做日志缓冲区写入内容,就存在为同一片内存区域竞争的问题。存在竞争,就存在开销,这篇文章大概介绍一下,oracle如何尽量降低这种开销。
二. 问题概述
oracle中不断地修改数据,源源不断地生成重做日志。oracle先将这些日志写入到重做日志缓冲区(一片内存区域),然后调用LGWR进程将这些日志写入磁盘上的联机日志文件(一般是三个,一个50M的样子)。一个联机日志文件写满之后,切换到另一个日志文件。如果oracle开启了归档模式,在切换日志文件的时候,会将上一个写满的日志文件拷贝一份,叫做归档日志文件,保存到一个地方(或许是另外一台服务器,以防意外发生,方便做实例恢复或介质恢复)。看起来一切都很完美,问题就出在将日志写入到重做日志缓冲区,如果并发量大,并且每一个回话都修改很多数据,那么对重做日志缓冲区的竞争就会异常激烈。很有可能导致cpu会花费大量时间在latch自旋上(也就是占用了cpu的时间,但是cpu什么都没干)。
三. 解决方案
问题1: 一个会话不停地修改数据,需要不停地往redo buffer(重做日志缓冲区)写入内容,也就是要不断地获取redo allocation latch(保护重做日志缓冲区的一种锁,控制并发)。非常影响效率,特别是高并发的时候,你不一定能获取到锁。
这里是否可以先把所有的redo生成,然后就获取一次redo allocation latch锁?答案是可以的,oracle中10g版本之后,提供了一种 private redo,也就是为每一个事物分配一个私有的redo buffer,你先在这里生成所有的重做日志。当事务提交的时候,获取一次redo allocation latch锁,将私有redo里面的内容,拷贝到公共redo buffer里面去。
引申 问题2:如果不停地修改数据,就会不停地生成undo数据块,undo数据块的改变也会生成redo buffer。而且这些必须跟描述数据改变的redo buffer成对出现,而且必须同时写入到重做日志文件。原因如下:当将一个脏数据块,写入磁盘数据块的时候,必须要求先将对应描述这条数据改变的redo记录和记录这条数据旧数据的undo数据块对应的redo记录写入到磁盘的重做日志文件。否则就保证不了数据的一致性。oracle在没有引入private redo之前,将描述数据块改变前的undo块当做一般的数据块处理,undo块发生改变,也生成redo,同时输出到重做日志文件。以前的这种机制存在如下问题:如果另一个会话需要到undo块里面寻找旧数据,但是undo块已经被刷新输出到磁盘,那么还需要到磁盘去调取出来,存在一定的I/O开销。同时,在引入private redo之后,无法保证描述一条数据改变的redo和undo一起刷新输出到重做日志文件。
为此,oracle引入了一个叫做IMU机制,也就是在内存区域另外为一个事务开辟一处私有的内存区域,专门用来存放描述undo数据块改变的redo记录。一个事务如果修改了10条数据,就会生成10条undo数据,从而产生10条描述undo改变的redo记录,存放在IMU里面。另外,加上描述数据本身改变的10条redo记录存放在private redo里面。总共是20条redo记录,如果事务提交的时候,就会将这20条redo记录合并成一条,从IMU和private redo拷贝到公共的redo buffer。当然,如果事务还没有提交,但是dbwn进程需要将其中3条脏数据刷新输出到磁盘,就会从imu和private redo里面分别取到这三条记录对于的redo记录,总共6条,合并成一条,然后拷贝到公共的redo buffer,进而刷新输出到磁盘。等到redo 刷新输出到磁盘成功,dbwn才能将脏数据刷新输出到磁盘。
为此,如果我们一个事务修改了很多数据,oracle的大概操作如下:
1. 获取成对的私有内存结构(也就是private redo:用来存放描述数据块的改变 和 IMU:用来存放描述对应undo数据块的改变),开启事务
2. 修改数据,为每一个受影响的数据块打上标记(以表示“拥有私有内存结构”),但不真正改变数据。
3. 将每一条还原改变向量(也就是描述undo数据改变)写到IMU池。
4. 将每一条重做改变向量(也就是描述数据块改变)写到私有redo区。
5. 将这两个内存结构的向量合并成一条重做改变记录。
6. 将重做改变记录复制到重做日志缓冲区(也就是公共 redo buffer),并改变这个数据块。(这么看来,我上面写的,事务还没结束,dbwn进程将脏数据写入磁盘是不可能发生的,因为,最后才改变数据块)
相关推荐
ORACLE 修改redo日志文件 大小的方法 供大家参考
Oracle备份恢复-redo文件损坏的各种场景恢复专题:redo文件损坏涉及到多种多样场景,具体场景可以分四大部分: 1、按照redo的状态可以分为current、active和inactive; 2、按照数据库归档模式可以分为归档和非归档;...
探索oracle redolog内部结构
Oracle工作总结——日志文件切换频率的调整 Oracle工作总结——日志文件切换频率的调整
Oracle_Undo与Redo的通俗
Oracle redo 异常暴增 日志挖掘 logminer
Oracle redo undo的说明解释
Redo log 是用于恢复和一个高级特性的重要数据,一个redo条目包含了相应操作导致的数据库变化的所有信息,所有redo条目最终都要被写入redo文件中去。Redo log buffer是为了避免Redo文件IO导致性能瓶颈而在sga中分配...
src =" node_modules/undo-redo-vuex/dist/undo-redo-vuex.min.js " > </ script > 模块 import undoRedo from "undo-redo-vuex" ; 用法 作为的标准, undo-redo-vuex可以用于以下设置: 如何在商店模块中...
Oracle DG下修改redo log和standby redo log日志大小.txt
丢失所有redo-数据文件-控制文件的恢复
oracle redo internal
介绍Oracle redo log 恢复步骤的文档,图文并茂
redo 维护redo 维护redo 维护redo 维护redo 维护redo 维护
python库。 资源全名:redo-2.0.3-py2.py3-none-any.whl
oracle日志,Undo日志记录某数据被修改前的值,可以用来在事务失败时进行rollback;Redo日志记录某数据块被修改后的值,可以用来恢复未写入data file的已成功事务更新的数据。
oracle 9i dba 认证教程学习笔记 第一章 oracle 数据库体系结构基础 1、oracle 数据库系统:为具有管理oracle数据库功能的计算机系统。 2、系统全局区(system global area):在数据库服务器上启动一数据库时的...
Redo log包含所有的数据库变化历史,数据库的所有操作变化,均按照写入重做日志缓冲区先于数据块缓冲区、写入重做日志文件先于写入数据文件;当发生提交动作时,将重做日志缓冲区变化刷到重做日志文件。
Kafka ConnectOraclekafka-connect-oracle是一个Kafka源连接器,用于从Oracle数据库捕获所有基于行的DML更改并将这些更改流式传输到Kafka。 变更数据捕获逻辑基于Oracle LogMiner解决方案。 仅从Oracle中提取已提交...