Oracle体系结构初探:聊聊REDO

本文详细介绍了Oracle数据库中的redo功能,包括redo日志的组成部分(RedoLogBuffer、LGWR和RedoLogFile),工作原理,以及在归档模式和非归档模式下的不同操作流程。作者通过实例和专业术语解释了事务重演和redo日志在数据库恢复中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章写了undo(文章链接:聊聊UNDO),这篇和大家一起聊聊redo。redo如果按照我的傻瓜翻译,意为再次去做、重新去做。Oracle官方对于redo的描述是:记录对数据所做的所有更改,包括未提交和已提交的更改;通过REDO来保证数据库的事务可以被重演,从而使得在故障之后,数据可以被恢复。

事务重演,这个名词稍微抽象一点点;我个人在抽象事务理解上比较愚笨,最开始在学习的时候花了不少功夫才理解这个名词。所以也想在这里举个例子和大家分享下我的拙见:

2024-04-18 00:00:00,我启动了Oracle数据库实例ORCL;

从此刻开始,ORCL对应的应用系统开始正常运行,开始向ORCL中增删改查数据;

2024-04-18 18:05:20,ORCL所在服务器突然意外关机了;

在关机的此时此刻有个INSERT操作,已经提交,但数据还未来得及写入磁盘;

2024-04-18 18:13:14,服务器恢复,开始启动ORCL数据库实例(此时的这个操作,其实应该叫做恢复ORCL实例);但是关机时提交的INSERT数据并没有写入磁盘,这不就造成了数据丢失嘛!Oracle多聪明,它此时会根据redo日志(online redo log)里的内容,将INSERT操作重新执行一遍,这就避免了此问题。

上面将INSERT操作重新执行一遍的过程,就是事务重演。

上面的例子,其实还有个专业的叫法:前滚;即已提交未写入的数据再次写入。

前滚是发生在Oracle实例恢复时的一个步骤。

那么正好在此处简单描述下实例恢复的过程:Oracle实例崩溃,进行实例恢复;① 先发生前滚,② 再打开数据库,③然后发生回滚。

以上是实例恢复的三个阶段,可以发现除了redo以外,undo也参与了实例恢复,因为发生了回滚。这也是在上一篇文章 《聊聊UNDO》中没有提到的UNDO的一个功能。

下面开始和大家分享下redo相关的一些基本知识内容,先看目录。

目录

redo相关组件

redo日志循环写

归档模式 

非归档模式 

redo日志状态

redo日志切换

redo日志操作


redo相关组件

在数据库中,redo的功能主要通过3个组件来实现:Redo Log Buffer、LGWR后台进程和Redo Log File。下面分别对这3个组件进行介绍。

  • Redo Log Buffer

Redo Log Buffer位于SGA中,是一块循环使用的内存区域,用来保存数据库变更的相关信息。这些信息以Redo Entries(重做条目)形式存储。

Redo Entries包含重构、重做数据库变更的重要信息(包括INSERT、UPDATE、DELETE、CREATE、ALTER或者DROP等)。而这些Redo Entries内容是被Oracle数据库进程从PGA复制到SGA中的Redo Log Buffer中的;多提一句的是SQL的语义解析,语法解析,执行计划都是在PGA中进行的,所以我们也就能推测到Redo Entries的信息格式大概是什么了。

Redo Entries主要是scn、时间戳、sql_redo等信息,这些信息可以通过Oracle的LogMiner工具去分析查看(配合v$logmnr_contents视图)。其中sql_redo就是产生redo的具体sql内容。

  • 后台进程LGWR

LGWR的作用是循环把Redo Log Buffer中的内容写出到Redo Log File中。当满足以下条件时,会触发LGWR进程:

  1. 事务提交时
  2. 每3秒钟
  3. 彻底关机前
  4. 在DBWN写入之前
  • Redo Log Files

重做日志文件,以组(group)出现。可以通过v$logfile查询相关日志文件信息。

select * from v$logfile

在这里重做日志文件又可以分为:ONLINE REDO LOG(在线重做日志)和 ARCHIVE REDO LOG(归档重做日志) 

ONLINE REDO LOG

Oracle以SQL脚本的形式实时记录数据库的数据更新,换句话说,按特定的格式实时保存已执行的SQL脚本到在线日志文件中,这个格式其实就是前文提到Redo Entries。

ARCHIVE REDO LOG

归档重做日志,简称归档日志,指当条件满足时,Oracle将在线重做日志以文件形式保存到硬盘(持久化)

从实际情况来看 ARCHIVE REDO LOG 其实就是 ONLINE REDO LOG 的备份。

redo日志循环写

那么ONLINE REDO LOG(在线重做日志)和 ARCHIVE REDO LOG(归档重做日志) 是如何参与Oracle的工作的呢?

先不急,我们再进一步探究下Redo Log File的细节信息:

Ⅰ:每个Oracle数据库都至少有2个Online重做日志组,每个组中至少有1个重做日志文件,这些Online重做日志组以循环方式使用。

Ⅱ:每组内的日志文件的内容完全相同,且保存在不同的位置,用于磁盘日志镜像,以做多次备份提高安全性。

Ⅲ: 我们是可以根据实际情况自定义添加、修改、删除日志组和日志文件的。

Ⅳ:在默认情况下,Oracle只有1个重做日志组处于活动状态;

数据库在开启归档模式状态下 和 非归档模式下的重做日志工作方式是不一样的,我们先来一起看下归档模式下的重做日志是如何工作的。

归档模式 

假设Oracle数据库有3个日志组:1#、2#、3#。

LGWR进程循环地向 1#日志组的 ONLINE REDO LOG 中写入特定格式的SQL脚本;

当1#日志组的 ONLINE REDO LOG 写满时,则将在线日志归档到硬盘,成为 ARCHIVE REDO LOG;

当1#日志组的 ONLINE REDO LOG 写满后,Oracle切换到2#日志组,开始向ONLINE REDO LOG写入特定格式的SQL脚本;

 如果1#日志组的 ARCHIVE REDO LOG 已经写完(归档结束),且2# 日志组ONLINE REDO LOG已经写满,那么2#日志组开始归档

⑤ 2# 日志组ONLINE REDO LOG已经写满,则切换至 3# 日志组,开始向ONLINE REDO LOG写入特定格式的SQL脚本;

 如果2#日志组的 ARCHIVE REDO LOG 已经写完(归档结束),且3# 日志组ONLINE REDO LOG已经写满,那么3#日志组开始归档

3# 日志组ONLINE REDO LOG已经写满,则重新切换至 1# 日志组,开始向ONLINE REDO LOG写入特定格式的SQL脚本;

循环以上过程

如果我们细心一点,可以发现一个细节:如果服务器磁盘性能差,归档速度慢,那么重做日志组切换就会出现问题。比如上述循环过程中,3#日志组的ONLINE REDO LOG写满后,1#日志组还在归档,那么此时是不会切换到1#日志组的,只能使用日志缓冲区,等待归档完毕之后才能覆盖写入。

非归档模式 

至于非归档模式状态下的redo日志循环写流程,就比较简单了,因为没有归档过程,如下图所示。还是假设有3个日志组:1#、2#、3#。只不过这次流程十分精简:

 LGWR进程循环地向 1#日志组的 ONLINE REDO LOG 中写入特定格式的SQL脚本;

② 1#日志组写满后,切换至2#日志组,LGWR进程循环地向 2#日志组的 ONLINE REDO LOG 中写入特定格式的SQL脚本;

2#日志组写满后,切换至3#日志组,LGWR进程循环地向 3#日志组的 ONLINE REDO LOG 中写入特定格式的SQL脚本;

3#日志组写满后,重新切换至1#日志组,LGWR进程循环地向 1#日志组的 ONLINE REDO LOG 中写入特定格式的SQL脚本;

循环以上过程

非归档模式下redo日志循环写

redo日志状态

关于redo日志状态,需要分成两块去讲。一块是redo日志组的状态,一块是redo日志文件的状态。

  • redo日志组状态

可以通过v$log视图查询redo日志组状态。

select group#,bytes,status from v$log;
SQL> select group#,bytes,status from v$log;

    GROUP#      BYTES STATUS
---------- ---------- ----------------
         1  209715200 INACTIVE
         2  209715200 CURRENT
         3  209715200 INACTIVE

通过上述输出结果可以看到这里已经有两种状态为INACTIVE和CURRENT,那么现在把REDO LOG组所有的状态都列出来。并给出相应解释:

Ⅰ:INACTIVE 

实例恢复不再需要联机重做日志组,它可能已经归档也可能未归档。

Ⅱ:ACTIVE

联机重做日志组是活动的,但是并非当前联机重做日志组,实例崩溃恢复需要该状态的日志,它可能用于块恢复,它可能已经归档也可能未归档。

Ⅲ:CURRENT

当前的联机重做日志组,这意味着该联机重做日志组是活动的。

Ⅳ:UNUSED

从未对联机重做日志组进行写入,这种状态的日志文件要么是刚增加的,要么是当日志不是current redo log时RESETLOGS操作后的状态。

Ⅴ:CLEARING

在ALTER DATABASE CLEAR LOGFILE 命令后正在将该日志重建为一个空日志,日志清除后其状态更改为UNUSED。

Ⅵ:CLEARING_CURRENT

正在清除当前日志文件中的已关闭线程,如果切换时发生某些故障,如写入新日志标题时的I/O错误,则该日志可以停留在该状态。

  • redo日志文件状态

可以通过v$logfile视图查询redo日志文件状态。

select group#,member,status from v$logfile;
SQL> select group#,member,status from v$logfile;

    GROUP# MEMBER                                   STATUS
---------- ---------------------------------------- -------
         3 /u01/app/oracle/oradata/ORCL/redo03.log
         2 /u01/app/oracle/oradata/ORCL/redo02.log
         1 /u01/app/oracle/oradata/ORCL/redo01.log

通过上述输出结果,可以看到这里STATUS(状态)列下并无数据,但实际上现在这个列中的值为NULL,那么我们把REDO LOG文件所有的状态都列出来。并给出相应解释: 

Ⅰ:INVALID

该文件不可访问

Ⅱ:STALE

该文件内容不完全,例如正在添加一个日志文件成员

Ⅲ:DELETED

该文件已不再使用

Ⅳ:NULL

该文件正在使用中

redo日志切换

redo日志切换,其实指的是redo日志组切换。redo日志组可以用两种方法去切换。但推荐的是用正常方式去切换。

  • 正常切换
alter system switch logfile;

切换例子如下 

  • 用发生检查点的方式去切换 
alter system checkpoint;

redo日志操作

  •  添加组成员

假如需要给1#日志组添加组成员;

先通过 select member from v$logfile;查询出对应redo日志文件路径。

再替换到下列语句中。

ALTER DATABASE
ADD LOGFILE MEMBER '/u01/app/oracle/oradata/ORCL/redo01.rdo'
TO GROUP 1

添加组成员有2个需要注意的地方:

Ⅰ:新增组成员不需要指定大小,因为每个组内的成员日志内容是一样的,所以大小和已存在的组成员一致。

Ⅱ:当组成员刚刚被添加时,它的日志文件状态是INVALID不可访问状态,如下图。

 那咋办嘞?

这时候就用到上文叙述过的redo日志组切换操作,操作结果如下图所示。

  • 删除组成员

删除语法很简单,如下所示,删除之前添加的1#日志组新成员redo01.rdo。

ALTER DATABASE DROP LOGFILE MEMBER '/u01/app/oracle/oradata/ORCL/redo01.rdo';

删除组成员有两个需要注意的地方:

Ⅰ:上述的删除语法只是在控制文件中,将日志组成员删除了;未真正在物理磁盘上将redo01.rdo文件删除;所以需要手动去对应路径下删除对应的redo01.rdo文件。

Ⅱ: 不能删除CURRENT状态下的日志组成员。

  • 添加组

还是和添加组成员一样,先找到其他组成员的存储路径,再替换到下面的代码中。

新建的组,可以指定组成员默认大小是多少。如下代码,指定的是组成员大小是200M。

ALTER DATABASE ADD LOGFILE GROUP 4 ('/u01/app/oracle/oradata/ORCL/redo04.log') 
SIZE 200M

添加组有2个需要注意的点:

Ⅰ:无法改变已存在的日志组成员大小;

Ⅱ:刚创建的日志组状态是UNUSED的,也可以进行手动切换日志组,进行状态的调整。


以上是关于redo的基本知识内容,按我自己的拙见是比较全面了。但redo与备份和恢复的关系没有提到太多。因为觉得内容太多,一章说完比较困难,后面再补吧。


另外也记录下一件小事:昨天,我对象发现了我头上长了一根白头发;这是我第一次长白头发,我真的要开始变老了,欸。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姜豆豆耶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值