Oracle——redo+undo总结
《Oracle------redo》
重做日志文件(redo log file)对数据库来说至关重要,他们是数据库的事务日志;
Oracle数据库维护着两类重做日志文件:在线重做日志文件(redo)和 归档重做日志文件(archive log),(归档重做日志文件实际上就是已填满的“旧”在线重做日志文件的副本)
这两类重做日志文件都是用于恢复的:
①:如果数据库所在主机掉电,导致实例失败,Oracle会使用在线重做日志将系统恢复到恰好在掉电之前的那个提交点;
②:如果磁盘驱动器出现故障(这是介质失败),Oracle会使用归档重做日志以及在线重做日志,以及之前的一个备份,将原在此驱动器上的数据恢复到某个时间点;
每个Oracle数据库都至少有两个在线重做日志,每个组中至少有一个成员(重做日志文件),在线重做日志组会以循环的方式使用;
Redo log的日志状态分为4种:
current:指的是当前日志文件,该日志文件是活动的,当前正在被使用的,进行崩溃恢复时,Current日志文件是必须的;
ACTIVE:是活动的非当前日志,可以已经完成归档也可能没有归档,在Crash恢复时会被用到;
inactive:非活动日志,在实例恢复时不再需要,但是在介质恢复时可能会用到,此状态的日志也可能没有被归档。
unused:该日志从未被写入,这类日志可能是刚被添加到数据库或者在resetlogs之后被重置。
《Oracle----undo》
REDO是为了重新实现你的操作,而UNDO相反,是为了撤销你做的操作,比如你得一个TRANSACTION执行失败了或你自己后悔了,则需要用ROLLBACK命令回退到操作之前。回滚是在逻辑层面实现而不是物理层面,因为在一个多用户系统中,数据结构,blocks等都在时时变化,比如我们INSERT一个数据,表的空间不够,扩展了一个新的EXTENT,我们的数据保存在这新的EXTENT里,其它用户随后也在这EXTENT里插入了数据,而此时我想ROLLBACK,那么显然物理上讲这EXTENT撤销是不可能的,因为这么做会影响其他用户的操作。所以,ROLLBACK是逻辑上回滚,比如对INSERT来说,那么ROLLBACK就是DELETE了。
注意:redo是用于在失败时恢复事务,undo则用来取消一条语句或一组语句的作用。与redo不同,undo是存储在数据库内部一组特殊的段中,称为undo段
1、insert:
第一条insert into t 语句会同时生成redo和undo,它锁生成的undo信息足以使insert小时,而redo信息则足以让这个insert再次发生;我们可以看到,块缓冲区里面存放着修改完的undo块、索引块、和表数据块,所有的这些块都被重做日志缓冲区中相应条目所保护;
2、update
update 生成的undo量更大,比insert要大,这是因为由于update需要保存数据修改前的映像;update语句还放在重做日志缓冲区中;
3、delete:
delete会生成undo,块被修改,并把redo发送到重做日志缓冲区;
4、commit
当事务提交时,Oracle会把重做日志缓冲区刷新输出到磁盘;
注意:
insert生成的undo最少;(因为Oracle只是记录了一个rowid)
delete生成的undo最多;(因为Oracle必须把整行的删除前映像记录到undo段中)
(索引的维护也是很高的,比如要更新有索引的列 那么会生成好几倍的undo)
commit的开销主要来自两方面:
第一:客户端与数据库直接往返通信量将会显著增大
第二:每次提交,都必须等待redo写至磁盘(在这种情况下,就会出现log file sync的等待事件)
执行commit时,剩下的工作:
1、为事务生成一个SCN号
2、LGWR将所有未写入磁盘的重做日志条目写至磁盘,并把SCN记录到在线重做日志文件中;
3、v$lock中会记录着我们的回话锁,这些锁都将被释放,而排队等待这些锁的会话都会被唤醒,从而可以继续完成他们的工作;
4、如果事务修改的某些块还在缓冲区缓存中,Oracle就会以一种快速的模式访问并清理;
redo 与 undo 日志的主要区别:
1、undo日志:在恢复时取消未完成事务的影响,忽略已经提交的事务
2、redo日志:忽略未完成的事务,重做已经提交事务的改变。
3、undo日志:先将修改后的数据写到磁盘——写commit到磁盘
4、redo日志:先写commit到磁盘——将修改后的数据写到磁盘
5、undo日志:要求数据在事务结束后立即写到磁盘,可能增加磁盘IO数
6、redo日志:要求我们在事务提交和日志记录刷新以前将所有修改过的块保留在缓冲区,可能增加事务需要的平均缓冲区数
《临时表和redo、undo》
在12C之前:
临时表的数据块不会生成redo,因此,临时表的操作不是可恢复的。不过临时表会生成undo,而且这个undo会计入日志,因此,临时表也会生成一些redo;临时表可以有约束,也可以这么说:正常表有的一切临时表都可以有;
临时表的DML操作,有如下特点:
1、insert会生成很少甚至不生成undo redo
2、临时表的update会生成永久表update大约一半的redo
3、delete在临时表上生成的redo与永久表上生成的redo同样多;
(临时表delete会生成很多redo,所以要避免进行delete操作,可以truncate;可以使用临时表进行insert和select操作)
在12C之后:
从Oracle12C起,我们可以通过设置temp_undo_enabled来将临时表的undo放在临时表空间中,由于临时表空间的任何数据变更都不会生成redo,所以当这个参数设置为TRUE时,任何临时表上的DML都会生产很少甚至不会产生redo;
(temp_undo_enabled的默认值是FALSE,如果将其改为TRUE的话,那临时表生成的redo量与12C版本之前是一样的)
ORA-01555: snapshot too old: -----这个错误是非常典型的错误:(它算的上是一个安全的错误,唯一的影响就是收到这个错误的查询无法继续处理)
产生这个错误的原因:
1、undo段太小,不足以支撑系统上执行的工作
2、程序夸commit获取数据
3、块清除
4、commit提交太频繁
解决的方法参考:
1、适当的设置参数undo_retention(要大于运行时间最长的事务所需的时间),我们可以通过v$undostat 来确定长时查询的持续时间,另外,请在磁盘上预留足够的空间,因为为了确保undo_retention,undo段可能也会有所增长;
2、使用手动undo管理时加大或增加更多的undo段,(不建议采用这种方法,强烈建议采用自动undo管理方式)
3、减少查询的运行时间(调优)。调优sql语句、
4、收集相关对象的统计信息。