欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

oracle的redo和undo

程序员文章站 2022-04-17 09:00:45
oracle实例在crash后,undo如何恢复的比较难于理解。下面详细描述了undo 的DML操作是如何保存在undo tablespace和在线归档日志中的。然后在分析下un...
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后续被用来做回退没有提交的修改。