实例恢复是使用联机日志文件(Online redo log)的内容,将数据库缓冲区缓存重新构建至崩溃之前的状态。这个重构过程将重演在崩溃时未被写至磁盘的数据块的相关 redo log 中提取出的所有变更。完成上述操作后,就能够打开数据库。此时,数据库仍然受到损坏,但是由于用户看到的实例已被修复,因此允许用户进行连接。实例恢复的这个阶段称为前滚,该阶段会取每条 redo log 将恢复所有变更(也就是针对已提交和未提交事务的数据块变更与撤消块变更),相应的数据块从数据文件载入数据库缓冲区缓存,并且应用相应的变更。随后,数据块会被写回磁盘。
向前回滚结束后,崩溃看上去似乎从未发生过。不过此时数据库中还存在未提交的事务,这些事务必须被回滚,Oracle 将在实例恢复的回滚阶段自动完成未提交事务的回滚操作。然而,上述操作则发生在数据库已被打开且使用之后。如果用户在连接时遇到某些需要回滚但是尚未回滚的数据,那么不存在任何问题。由于前滚阶段会填充保护未提交事务的撤消段,因此服务器能够以正常的方式回滚变更,从而实现读一致性。
让我们先来看看下面的场景:
用户 JOHN 启动了一个事务。JOHN 使用某些新值更新某个表的一行,其服务器进程则将旧值复制至一个撤消段。但是完成这些更新之前,服务器进程会将变更写入日志缓冲区。用户 ROOPESH 也启动了一个事务。两个用户都未提交事务,也没有在磁盘上写下任何数据。如果此时实例崩溃,那么不存在(甚至重做日志中也不存在)与任一个事务相关的记录。因此,两个事务都不会被恢复,但这并不是一个问题。因为都未被提交,所以不应当恢复这两个事务(未提交的工作绝不会被保存)。
随后,用户 JOHN 提交了自己的事务。这个提交操作会触发 LGWR 进程将日志缓冲区中的内容刷新到联机重做日志文件,也就是说,此时重做日志文件内存在:
1)JOHN 的事务对表和撤消段的更改
2)ROOPESH 的事务对表和撤消段的更改
3)JOHN 的事务的提交记录
只有在 LGWR 进程结束后,“commit complete(提交完成)”消息才会被返回给 JOHN 的用户进程。但是,数据文件中仍然不会写入任何数据。如果此时实例失败,那么前滚阶段会重新构造这两个事务(1,2,3),不过处理完所有重做后仍然不会得到针对 ROOPESH 的更新操作的提交记录,这将通知 SMON 进程回滚 ROOPESH 所做的变更(2),同时保留 JOHN 所做的变更。
缓冲区缓存中已更改的块由数据库写入器(DBWn)进程执行检查点操作。应用于这些块的变更向量已由 LGWR 进程写入重做流。DBWn 根据一个懒惰算法来写入,LGWR 根据一个主动算法写入,该主动算法接近实时执行,在执行 COMMIT 时是实时执行。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于