一、数据改变的方法和步骤
1、Oracle数据改变的四步法
Oracle在处理数据变更时,不是直接在数据文件中找到数据项并进行修改,而是通过四个关键步骤来实现数据变更。
第一步:创建数据项变更描述
在这一步中,Oracle创建一个描述如何变更数据项的redo change vector。
第二步:创建原始数据项的重构描述
Oracle创建一个描述,以便在需要时重新创建原始数据项。
第三步:创建重构描述的描述
这一步涉及到创建一个描述,这个描述说明了如何创建第二步中的重构描述。
第四步:变更数据项
最后,Oracle实际变更数据项。
2、数据变更的顺序
在OLTP事务中更新单行数据时,步骤的实际顺序与上述步骤有所不同,实际顺序为3, 1, 2, 4。两个redo change vectors合并为一个redo change record,并在修改undo块和数据块之前复制到redo log(buffer)中。
总结
Oracle在数据文件中的每个变更都会伴随着创建一个undo记录(这也是对数据文件的变更)。同时,Oracle会在redo log中放入描述如何进行我们的变更以及如何进行其自身变更的描述。
3、数据变更步骤顺序差异原因
Oracle在处理数据变更时的步骤顺序与列出的顺序不同。这是因为Oracle在执行数据变更时,会先创建用于撤销变更的描述(undo change vector),然后再创建用于执行变更的描述(redo change vector)。这种顺序确保了数据的一致性和事务的可回滚性,同时也优化了日志空间的使用。
具体的执行顺序是:3, 1, 2, 4。这意味着在修改数据块之前,会先合并两个重做变更向量(redo change vectors)到一个重做变更记录中,并将其复制到重做日志(buffer)中,然后依次修改undo块和数据块。
4、实际执行顺序
1.为undo记录创建改变向量;
2.为数据块创建改变向量;
3.合并改变向量,并将构造好的redo记录写进重做日志缓冲区;
4.将undo记录插入到undo中;
5.真正改变数据块
5、执行顺序优势
Oracle在处理数据变更时,会先创建撤销变更向量(undo change vector),然后再创建执行变更向量(redo change vector)。
- 这种顺序允许Oracle在执行实际的数据变更之前,已经有了一个完整的撤销计划,确保了数据的一致性和可恢复性。
- 通过先创建撤销变更向量,Oracle可以确保即使在事务未提交的情况下,数据的变更也能被正确地撤销,保持数据的一致性。
- 撤销变更向量的先行创建,强化了事务的原子性,即事务中的操作要么全部成功,要么全部失败,不会留下不完整的状态。
- 这种顺序有助于Oracle管理并发事务,因为它允许系统在多个事务同时进行时,正确地处理数据的可见性和一致性问题。
- 先创建撤销变更向量意味着在任何数据变更发生之前,系统已经有了一个恢复点,这对于系统的故障恢复和数据恢复至关重要。
二、Oracle对Log Buffer的访问控制机制
1、基本概念
-
Redo Allocation Latch
Oracle使用redo allocation latch来保护redo log buffer。当一个进程需要在log buffer中分配空间时,它尝试获取redo allocation latch。一旦进程获得该latch的独占所有权,它就可以在buffer中为其想要写入的信息预留空间。这避免了多个进程覆盖同一块内存区域的风险。 -
Private Redo Thread
从Oracle 10g开始,Oracle在SGA中分配了内存块,作为个别会话在事务期间的迷你log buffer。当会话提交时,它会将其私有log buffer的内容复制到公共log buffer中。这种复制可能会因为各种原因提前发生。 -
System Global Area (SGA)
SGA是Oracle数据库中一个重要的内存区域,包含了多个组件,包括log buffer。Log buffer有时也被称为公共log buffer或公共redo thread,是SGA中的一小块内存,用作当前redo日志文件的窗口。只有日志写入进程(Log Writer)可以将buffer内容传输到磁盘。 -
Log Parallelism
Oracle 9.2通过log_parallelism参数引入了多个log buffers的选项,以提高可扩展性。这个选项在10g中得到了进一步的发展,如果拥有多个CPU,Oracle至少会有两个公共log buffers(redo threads)。 -
Memory Management in Shared Pool
与buffer cache类似,shared pool负责跟踪free memory,获取memory以及在需要时提供free memory。Shared pool受到shared pool latch的保护,管理着内存的分配和释放。Oracle通过redo allocation latch来确保对log buffer的独占访问,防止多个进程同时写入导致的数据覆盖问题。从10g版本开始,Oracle引入了private redo thread,允许每个会话有自己的迷你log buffer,进一步提高了系统的并发处理能力。SGA中的log buffer作为公共资源,由日志写入进程负责将内容写入磁盘。此外,Oracle通过shared pool和shared pool latch来管理内存,确保内存资源的有效利用。这些机制共同确保了Oracle数据库在处理物理I/O时的高效性和稳定性。
2、Redo Allocation Latch的保护机制
- 独占访问控制
进程尝试获取redo allocation latch以在log buffer中分配空间。一旦进程获得latch的独占所有权,它就能在buffer中预留空间来写入信息。这避免了多个进程覆盖同一块空间的风险。 - 空间不足的处理
如果会话在获取redo allocation latch后发现空间不足,它会释放latch。然后获取redo writing latch来检查lgwr是否正在写入。如果lgwr没有写入,会话会标记lgwr进行写入,然后释放这个latch。会话进入等待log buffer空间的状态。lgwr完成写入后需要检查是否有会话在等待log buffer空间,如果有,则标记它们继续处理。 如果lgwr已经在写入,会话简单地返回redo allocation latch并再次尝试分配空间,因为lgwr的当前写入应该能释放一些log buffer空间。 - 事务处理
在事务完成时,进程将所有私有存储的redo复制到公共redo log buffer中。这意味着进程每笔事务只获取一次公共redo allocation latch,而不是每次更改都获取。
3、Redo处理的简化
-
连续流生成
Oracle持续生成redo记录流,并尽可能快地将它们泵入redo log。最初,这些记录被写入共享内存区域,即redo log buffer。 -
磁盘写入和文件重用
Oracle需要将buffer写入磁盘,并且出于操作原因,实际上将“连续”流写入一组预定义文件——在线redo log文件。在线redo log文件的数量有限,因此需要不断地以轮询方式重用它们。 -
触发写入的条件
如果分配导致使用的log buffer空间超过三分之一或1MB,或者redo记录是一个提交记录,则需要发布lgwr进行写入(但首先获取redo writing latch以检查lgwr是否已经在写入)。
4、Redo Allocation Latch的工作机制
- 获取Latch
进程尝试获取Redo Allocation Latch,以便在Log Buffer中分配空间。 - 预留空间
获取到Latch后,进程可以在Buffer中标记要写入信息的空间。 - 释放Latch
分配完空间后,进程会释放Redo Allocation Latch,以便其他进程可以使用。
5、处理空间不足的情况
- 检查空间
如果在分配空间时发现Log Buffer中没有足够的空间,进程会释放Redo Allocation Latch。 - 获取Redo Writing Latch
进程会获取Redo Writing Latch,检查lgwr是否正在写入。 - 等待Log Buffer空间
如果lgwr没有在写入,进程会将自己放入等待Log Buffer空间的队列中。 - 检查等待的会话
当lgwr完成写入后,需要检查是否有会话在等待Log Buffer空间,如果有,则通知它们继续处理。
6、Redo Wastage问题
- lgwr的写入过程
lgwr在响应写入请求时,会获取Redo Allocation Latch,并将自由空间的起始点移动到当前块的末尾。 - 避免Redo Wastage
lgwr在写入时会将所有相关的提交记录(包括触发写入的记录和其他"搭便车"的提交记录)一起写入,以减少Redo Wastage。
7、多进程竞争Redo Allocation Latch的问题
- 资源消耗
如果有大量进程不断竞争Redo Allocation Latch,可能会导致资源(如CPU)的隐形消耗,或者增加会话的睡眠时间。 - 获取共享模式下的Latch
当其他进程以共享模式持有Latch时,可以获取共享模式下的shareable latch。
三、私有Redo buffer
-
私有log buffer的定义
私有log buffer,也称为私有Redo线程,是Oracle 10g引入的一个特性。 它们是SGA中分配给各个会话的小块内存,作为迷你log buffer,用于存储个别会话在事务持续期间产生的Redo数据。 -
私有log buffer的作用
私有log buffer允许每个会话在事务过程中拥有自己的Redo数据存储空间。 这种设计减少了对公共Redolog buffer的竞争,提高了并发事务处理的效率。
1、私有log buffer的工作流程
- 事务处理中的私有log buffer
在事务过程中,会话产生的Redo数据首先存储在私有log buffer中。私有log buffer减轻了对公共Redolog buffer的压力,因为每个会话都有自己的Redo数据存储空间。 - 私有log buffer与公共log buffer的交互
当事务完成时,私有log buffer中的Redo数据会被复制到公共Redolog buffer中。 这个过程称为“复制”,是事务提交过程中的一个重要步骤。 - 复制的触发条件
复制可以在事务提交时发生,也可能因为其他原因提前发生。 例如,如果私有log buffer满了,或者系统需要确保数据的持久性,复制可能会提前触发。
2、私有Redo线程在整个事务处理中的角色
- 提高事务处理效率
私有Redo线程减少了对公共Redolog buffer的竞争,从而提高了事务处理的效率。每个会话只需要在事务开始和结束时与公共Redolog buffer交互,减少了锁争用和等待时间。 - 确保数据一致性和持久性
私有Redo线程确保了在事务提交时,所有更改都能被记录下来,并且能够被恢复。 通过将私有Redo数据复制到公共Redolog buffer,系统确保了数据的一致性和持久性。 - 优化资源利用
私有Redo线程允许Oracle更有效地利用SGA内存资源。通过为每个会话分配适量的内存空间,系统可以平衡内存使用,避免资源浪费。 - 支持并发和可扩展性
私有Redo线程支持高并发环境下的事务处理,提高了系统的可扩展性。在多用户和高负载情况下,私有Redo线程可以提高系统的吞吐量和响应速度。
四、In-Memory Undo (IMU) 机制
Oracle 10g 引入了IMU的概念,即在SGA内存中分配的小型log buffer,这些缓冲区可以分配给各个会话,用于存储事务期间需要撤销的数据块的重做信息。
- 事务处理
每个事务的提交都会将in-memory undo复制到公共log buffer。 - 提前复制原因
克隆undo段头部块会触发事务表一致性读取回滚统计的增加。 - 自动撤销管理 (AUM)
Oracle 9i引入的机制,旨在减轻DBA指定撤销(回滚)段的数量和大小的工作负担。 - IMU锁存器访问
每次数据更改都会访问IMU锁存器。 - Private Redo标记
标记受影响的数据块为“有Private Redo”,但不改变数据块本身。 - 撤销更改向量
将每个撤销更改向量写入选定的IMU池。 - 撤销记录
存储在撤销表空间中的信息单元,描述如何撤销对数据块的单个更改。
五、内存结构
- 公共重做线程的数量:
公共重做线程的数量由cpu_count参数决定,计算公式为ceil(1 + cpu_count / 16)。 - xkcrfstrand的作用: xkcrfstrand负责处理“向前”的变更向量。 它还持有关于传统“公共”重做log buffer的信息。
- xktifp的作用: xktifp负责处理撤销变更向量。它与xkcrfstrand一起,共同管理数据库的重做和撤销操作。 xkcrfstrand和xktifp都是Oracle数据库内部的内存结构,用于管理事务的重做和撤销操作。这些结构对于数据库的一致性和恢复至关重要。对于xktifp中的每个条目,在xkcrfstrand中都有一个对应的Private Redo条目。除此之外,xkcrfstrand中还有一些额外的条目,这些条目是为传统的“公共”重做线程准备的。
- 动态性能视图:
通过v和gv视图,SYS账户可以查看Oracle程序运行时使用的内部结构。这些视图提供了对xkcrfstrand和xktifp等内存结构的访问。 - xkcrfstrand的详细信息 xkcrfstrand中的每个条目都有自己的重做分配锁。每个公共重做线程还额外有一个redo copy latch。
- xktifp的详细信息 xktifp中的内存池数量取决于持有数组的大小。
六、IMU和Private Redo
-
IMU(In-Memory Undo)
Oracle 10g中引入的IMU是SGA中的一部分内存,作为一组小型log buffer分配给各个会话,用于存储事务期间需要撤销的块的重做信息。提交时的行为:当事务提交时,IMU中的信息会被复制到公共log buffer中。 -
Private Redo(Private Redo)
自Oracle 10g起,SGA中分配了一部分内存作为迷你log buffer,这些缓冲区可以分配给各个会话,用于存储事务期间的私有日志信息。提交时的行为:事务提交时,会将私有log buffer的内容复制到公共log buffer中。
七、提交时与公共log buffer的关联
-
IMU与公共log buffer
- 复制过程:事务提交时,IMU中的信息会被复制到公共log buffer中。
- 复制时机:复制可能会因为各种原因提前发生。
- 后续处理:复制完成后,dbwr(数据库写入进程)会将等待的会话标记为继续处理,此后该会话生成的任何重做信息都会按照传统方式进入公共重做线程。
-
Private Redo与公共log buffer
- 复制过程:事务提交时,Private Redo线程中的内容会被复制到公共log buffer中。
- 复制时机:复制也可能因为各种原因提前发生。
- 后续处理:复制完成后,会话的后续重做信息会进入公共重做线程,而私有线程仍然绑定到该会话,直到会话提交。
-
统计和记录
- 重做记录:Private Redo最初由前台会话创建,这部分重做信息会被记录在dbwr的redo record和重做大小统计中。
- 撤销记录:而撤销信息则会被记录在前台会话的撤销变更向量大小中。
-
公共重做分配锁
锁的使用:由于Private Redo的存在,一个事务在整个过程中只需要获取一次公共重做分配锁,而不是每次变更时都获取。 -
事务提交后的公共log buffer处理
传统处理:Private Redo复制到公共log buffer后,传统的log buffer处理接管后续操作。
IMU和Private Redo:它们都是Oracle 10g中引入的优化,用于提高事务处理效率。提交时的行为:事务提交时,IMU和Private Redo中的信息都会被复制到公共log buffer中,然后由公共log buffer继续处理。




