oracle的redo和undo

oracle实例在crash后,undo如何恢复的比较难于理解。下面详细描述了undo 的DML操作是如何保存在undo tablespace和在线归档日志中的。然后在分析下undo保存两份信息的原因。

首先,看看undo是如何保存在undo tablespace中的。 –oracle redo 包含 undo

– Checkpointing 导致

. 脏块被写到数据文件中

. 同样的包含undo信息的buffers 也被写到undo tablespace

概述: – 创建tablespace test_undo

– 创建表 test_undo_tab in tablespace test_undo

– Insert two rows with txt – teststring1, teststring2 in test_undo_tab 然后执行checkpoint。

– 切换日志,新在线日志中没有包含string teststring1

– 切换undo表空间到表空间undotbs2

– 将字段从 teststring1 更新为teststring_uncommitted,但是不commit

– 在另外一个会话,将字段值从 teststring2 更新为teststring_committed并commit。

– 检查是不是字段的修改前后的值都写到现在的redo log文件中。

– 检查undo表空间没有包含修改前的值,例如:

teststring1 和 teststring2 作为undo信息还在buffer cache中,checkpoint还没有发生。

– 执行手工的checkpoint,buffers中的信息包含undo信息都会刷新到磁盘中。

– 检查undo表空间是否包含修改前的值。例如teststring1 和 teststring2


执行:


– 正在使用的undo tablespace – sql>sho parameter undo_tablespace NAME TYPE VALUE ———————————————– —————————— undo_tablespace string UNDOTBS1


– 创建一个新的undo表空间undotbs2 SQL> create undo tablespace undotbs2datafile ‘/paic/app/dbshare/undotbs2.dbf’ size 100m;


– 创建一个表空间test_undo SQL> drop tablespace test_undo includingcontents and datafiles; create tablespace test_undo datafile ‘/paic/app/dbshare/test_undo.dbf’ size 128k;


– 在上面创建的表空间中创建测试表test_undo_tab SQL> drop table test_undo_tab purge; create table test_undo_tab(txt char(1000)) tablespace test_undo;


– 在test_undo_tab表中insert两条记录并commit – SQL> insert into test_undo_tab values(‘teststring1’); insert into test_undo_tab values (‘teststring2’); commit;


– 执行手工checkpoint,然后上述修改写到数据文件中。 SQL>alter system checkpoint;


– 将当前的undo表空间切换为undotbs2 SQL>alter system set undo_tablespace =undotbs2; show parameter undo_tablespace NAME TYPE VALUE ———————————————– —————————— undo_tablespace string UNDOTBS2


– 切换redo log,这样当前的redolog没有包含任何信息。 SQL>alter system switch logfile;


– 找出现有的redo log SQL> col member for a30 select member, l.status from v$log l, v$logfile f where l.group# =f.group# and l.status = ‘CURRENT’;

MEMBER STATUS ———————————————- +DATA_TEST1_DG/test/onlinelog CURRENT /group_2.384.865438859


– 打开一个会话更新一条记录但是不commit– SQL> update test_undo_tab set txt = ‘teststring_uncommitted’ where txt = ‘teststring1’;


– 打开另外一个会话,修改第二条记录,并commit – SQL> update test_undo_tab set txt = ‘teststring_committed’ where txt = ‘teststring2’; commit;


– 然后检测redo log文件中是否包含redo和undo的DML操作 (committed and uncommitted)– [grid@cnsh230235 ~]$ asmcmd cp+DATA_TEST1_DG/weiyj/onlinelog/group_3.401.865438859 /oracle_grid/grid/group_2 copying+DATA_TEST1_DG/weiyj/onlinelog/group_2.384.865438859 ->/oracle_grid/grid/group_2 [grid@cnsh230235 ~]$ strings group_2 |greptest teststring_uncommitted teststring1 teststring_committed teststring2


– 检测数据文件没有包含修改的值,比如teststring_committed 和 teststring_uncommitted ,因为checkpoint还没有发生,脏块还没有写入到磁盘。 [oracle@node1 oracle]$ strings/u01/app/oracle/test_undo.dbf|grep teststring

teststring2 , teststring1


– 检测undo表空间也没有包含更新前的值,比如undo的信息teststring1 和teststring2还在buffer cache中,checkpointing还没有发生。 [oracle@node1 oracle]$ strings/u01/app/oracle/undotbs2.dbf|grep teststring


– 执行手工的checkpoint,这样buffers中的undo信息就被刷新到磁盘中。 SQL> alter system checkpoint;


– 检测数据文件包含了修改前后的值,(both committed anduncommitted) ,例如: teststring_committed andteststring_uncommitted,因为checkpointing发生后, buffers中的脏块被刷新到磁盘中。 [oracle@node1 oracle]$ strings/u01/app/oracle/test_undo.dbf|grep teststring

teststring_committed , teststring_uncommitted


– 检测undo表空间中也包含了修改前的值,比如teststring1 and teststring2 [oracle@node1 oracle]$ strings/u01/app/oracle/undotbs2.dbf| grep teststring

teststring2 teststring1


– 清理测试文件 – SQL>drop tablespace test_undo includingcontents and datafiles; alter system set undo_tablespace=undotbs1; drop tablespace undotbs2 including contents and datafiles;

现在可以得出结论:

–Log writer 会写一个事务中每个DML的undo和redo (committed/uncommitted) 和是否发生checkpoint没有关系。

– 发生checkpoint时,

. database buffer cache中的undo信息会写到undo表空间中

. 脏块Dirty buffers中包含了committed/uncommitted数据会被写入到数据文件中。

如果是一个正在运行中数据库,这意味着: – 数据文件可能会包含未提交的信息 (被修改的buffers、但是没有commited、发生checkpoint) – 提交的数据没有在数据文件中(提交后,checkpointing还没有发生) – 修改后提交的redo/undo会被写入到redo logs中 (Lgwr writes on commit). – 修改后没有提交的redo/undo可能被写入到redo logs中(Lgwr writes every 3 seconds) – 除了redo logs文件,undo information § . 可能会在buffer cache中 (修改后checkpoint还没有发生) § . checkpoint发生后会被写入到undo表空间中。 § . 当一个事物活动、没有结束时,undo信息是不会被覆盖的。

另外一个问题时,为什么undo信息需要保存两份,分别保存在undo表空间和redo logs文件中。

让我们看看如果undo信息只保存在redo log文件中,会发生什么情况。

只要修改的数据已经写到数据文件中,redo log可以被重用。

如果进行了修改,但是没有commit的情况下:

– 修改被写到了redo log文件中

– 发生了checkpoint

– uncommitted的修改被写到了数据文件中

– 如果决定回退修改

– 如果redo log文件没有被覆盖重用

. 搜索整个redo log文件,然后进行回退

如果覆盖重用了

. undo的信息就不能进行恢复了。

有人可能会说,如果redo log包含了活动的undo信息,就不允许覆盖重用, 我们就可能只需要保存undo到redo log文件中了。这种方案也是不可行的,因为:

– redo log文件的大小将会增至的非常大,因为极端情况下,一个用户可能过几个月才结束一个事务。

– 为了回退一个修改,需要读取大量redo log文件中的数据,包括redo和undo信息,这将带来性能极大的下降。

– redo log文件将会出现争用,因为它们被用作:

. 同时写 redo and undo

. 用来读取回退修改

所以,undo信息除redo log之外还需要独立保存用来回退没有commit的事务。Undo信息会保存在undo buffers/undo tablespace中,用来:

– read consistency

– flashback query

– flashback version query

现在, 让我们看看如果undo只保存在undo表空间中,会出现什么情况。

情况– I – 进行修改但是没有提交

– 修改的redo信息保存在redo log文件中

– 修改的undo信息保存在buffer cache

– 修改的undo信息还没有保存到undo表空间中,因为还没有发生checkpoint

– 实例 crashes

– 保存在buffer cache的undo信息被清除了。

– 作为instance recovery的一部分, redo被应用后,数据文件保护了未commit的数据。

– 数据库不能被打开,因为没有undo信息来需要回退未提交的修改,这样数据库处于不一致的状态。

情况– II – 进行表空间的hot backup

– 表空间的数据库文件丢失或者损坏了

– 将表空间offline,然后从备份restore数据文件

– recover the datafile

– redo logs和archivelogs包含了提交和未提交事务的redo数据

– redo logs和archivelogs没有包含undo的信息(根据假设).

– 作为recovery的一部分, 提交和未提交事务的redo数据可以读取并应用。

– 表空间还是不能修改为在线,因为需要进行回滚的undo信息没有找到。

所以,为了解决上面的问题,undo也需要保存在redo log文件中。在实例或者media recovery时,进行向前回滚,redo的信息(redo log文件中)被应用到数据文件,undo的信息被用来生成undo segments。在实例或者media recovery时,进行向后回滚,这些undo segments后续被用来做回退没有提交的修改。

(0)
上一篇 2022年3月22日
下一篇 2022年3月22日

相关推荐