oracle redo和undo简述

一、redo

重做日志文件(redo log file)是数据库的事务日志。oracle有在线重做日志和归档重做日志。

重做日志文件都用于恢复,万一实例失败或介质失败,它们就能恢复数据库到这个“意外”发生前的时间点。

二、undo

undo用于取消一条语句或一组语句的作用。

undo在数据库内部存储在一组特殊的段中,这称为undo段(undo segment)。“回滚段”(rollback segment)和“undo 段”(undo segment)一般认为是同义词。

undo操作数据库只是逻辑地恢复到原来的样子,所有修改都被逻辑地取消,但是数据结构以及数据库块本身在回滚后可能大不相同。

oracle回滚时,它实际上会做与先前逻辑上相反的工作。对于每个insert,oracle会完成一个delete。对于每个delete,oracle会执行一个insert。对于每个update,oracle则会执行一个“反update”,或者执行另一个update将修改前的行放回去。

三、redo和undo如何协作

尽管undo信息存储在undo表空间或undo段中,但也会受到redo的保护。换句话说,会把undo数据当成是表数据或索引数据一样,对undo的修改会生成一些redo,这些redo将计入日志。

redo负责记录做了什么,undo负责使修改消失。

如果系统奔溃,恢复作为一个两步的过程来完成。首先前滚,把系统放到失败点上,然后回滚尚未提交的所有工作。这个动作会再次同步数据文件。它会重放已经进行的工作,并撤销尚未完成的所有工作。

我的理解:

redo的作用
比如在oracle上做了事务1,事务2,事务3,当事务3执行到一半时系统奔溃了。oracle重启后,回到过去的某个时间点(事务1之前的时间点),从归档重做日志里,重新执行事务1,事务2。由于失败时事务3并未提交,所以不影响数据库。

undo的作用
同样在oracle上做了事务1,事务2。当事务2做完后想要反悔事务2做的修改,那么数据库从undo段里找到它的原值,并恢复回去。

还有两个影响是:

联机重做日志写到归档文件的前后,内存中被修改数据块刷新输出到磁盘数据块的前后。

四、提交和回滚

1、commit
在oracle事务中,分多次提交并不能节约系统资源,实际上只是增加了资源的使用。提交1行和提交10000行它“提交成本”是一样的。

commit要做的内容:
将内存中被修改的数据块写回磁盘

生成SCN
为事务生成一个SCN。SCN是oracle使用的一种简单的计时机制,用于保证事务的顺序,并支持失败恢复。SCN还用于保证数据库中的读一致性和检查点。可以把SCN看作一个钟摆,每次有人commit时,SCN都会增1。

写归档重做日志
LGWR将所有余下的缓存重做日志条目写到磁盘,并把SCN记录到在线重做日志文件中。这一步就是真正的commit。如果出现了这一步,即已经提交。事务条目会从V$TRANSACTION中“删除”,这说明我们已经提交。

释放锁
V$LOCK中记录这我们的会话持有的锁,这些所都将被释放,而排队等待这些锁的每一个人都会被唤醒,可以继续完成他们的工作。

清理缓存
如果事务修改的某些块还在缓冲区缓存中,则会以一种快速的模式访问并“清理”。

其中最耗时的是LGWR写归档重做日志,但是LGWR在后台是以异步方式执行,它会3秒自动刷一次,或到一定容量自动写入磁盘,所以每次提交的时间都是差不多的。

2、rollback
rollback要做的内容:
撤销已做的所有修改。其完成方式如下:从undo段读回数据,然后实际上逆向执行前面所做的操作,并将undo条目标记为已用。如果先前插入了一行,rollback会将其删除。如果更新了一行,回滚就会取消更新。如果删除了一行,回滚将把它再次插入。

会话持有的所有锁都将释放,如果有人在排队等待我们持有的锁,就会被唤醒。

3、块清除
如果块需要清理(延迟清除),第一个接触这个数据的查询将带来一些额外的处理。

4、临时表和redo/undo
临时表不会为它们的块生成redo,但是临时表会生成undo。由于undo数据必须建立日志,因此临时表会为所生成的undo生成一些重做日志。

关于临时表上的DML活动,可以得出以下一般结论:
insert会生成很少甚至不生成undo/redo活动。
delete在临时表上生成的redo与正常表上生成的redo同样多。
临时表的update会生成正常表update一半的redo。

5、什么操作会生成最多和最少的undo?
一般来讲:
insert生成的undo最少,因为insert前就是空的,oracle只要记住插入记录的rowid。
update排名第二,因为我们往往更新一行记录的几个列,一小部分的数据,undo要记住这些数据块的“前映像”。
delete生成的undo最多,因为oracle必须把整行的前映像记录到undo段中。

6、什么操作生成最多和最少的redo?
delete生成的redo包括了undo(数据的前映像)和删除的动作。
insert生成的redo包括了undo和插入的动作(数据的后映像)。
update生成的redo包括了undo和数据的后映像。

我觉得delete和insert在生成redo上是差不多的,一个是空变为有数据,一个是有数据变为空。因为redo包含了前映像和后映像,upudate往往数据量很小,并不是整行数据。

所以,结果是:
update < ( delete ≈ insert ) 五、ORA-01555:snapshot too old错误 ORA-01555:snapshot too old表示在undo段找不到原值了,导致接收到这个错误的查询无法继续处理。 发生ORA-01555错误的原因,一般有3个: undo段太小,不足以在系统上执行工作。 你的程序跨commit获取(实际上这是前一点的一个变体)。我们在上一章讨论了这种情况。 块清除。 解决方案: 减少查询的运行时间(调优)。 手动增大undo段。 适当地设置参数UNDO_RETENTION。 收集相关对象的统计信息。