实例恢复时自动的、不可避免的,那么如何才能调用实例恢复呢?答案是使用STARTUP命令。在实例启动时,加载控制文件之后,打开数据库之前,SMON进程会查看所有数据文件和连接重做日志文件的文件头。此时,如果已经出现了实例失败,由于文件头没有全部同步,因此SMON进程会发现实例失败,从而进入实例恢复例程,而数据库只能在前滚阶段结束之后才能被真正地打开。
如果执行了STARTUP命令,那么绝对不会丢失任何数据。在发生任何崩溃之后,都应当执行STARTUP命令并查看崩溃的程度。这个命令可以解决所有问题。
重做日志流中始终存在足够的信息,因此不仅能够重新构造发生崩溃前进行的所有操作,而且能够重新构造回滚崩溃时正在进行的事务所需的撤销信息。分析下面的场景:
用户John启动了一个事务。John使用某些新值更新某个表的一行,其服务器进程则将旧值复制至一个撤销段。但是完成这些更新之前,服务器进程会将变更写入日志缓冲区。用户Joo也启动了一个事务。两个用户都未提交事务,也没有在磁盘上写下任何数据。如果此时实例崩溃,那么不存在(甚至重做日志中也不存在)与任一个事务相关的记录。因此,两个事务都不会被恢复,但这并不是一个问题。因为都未被提交,所以不应当恢复这两个事务(未提交的工作绝不会被保存)。
随后,用户John提交了自己的事务。这个提交操作会触发LGWR进程将日志缓冲区中的内容刷新到联机重做日志文件,也就是说,此时重做日志文件内存在joh和Joo的事务对表和撤销段的更改以及针对John的事务的提交记录。只有在LGWR进程结束后,“commit complete(提交完成)”消息才会被返回给John的用户进程。但是,数据文件中仍然不会写入任何数据。如果此时实例失败,那么前滚阶段会重新构造这两个事务,不过处理完所有重做后仍然不会得到针对Joo的更新操作的提交记录,这将通知SMON进程回滚Joo所做的变更,同时保留John所做的变更。
然而,如果DBWn进程在实例崩溃前将某些数据块写入磁盘,那么又将出现怎样的情况呢?John(或者另一个用户)可能频繁地重新查询与其相关的数据,而Joo对数据进行了未提交的更改,并且不再查看这些数据。因此,DBWn进程将确定在磁盘上优先写入Joo所做的变更,然后再写入John所做的变更。DBWn进程总是会在磁盘上先写入不活跃的数据块,然后再写入活跃的数据块。因此,此时数据文件中存储了JOO的未提交事务,但是丢失了John的已提交事务。这是最糟糕的损坏类型。不过经过仔细考虑可以发现:即使此时实例崩溃,前滚仍然能够解决这个问题。重做流中始终存在重新构建已提交变更所需的足够信息,其原因显而易见,因为提交操作在DBWn进程完成写入之前不会结束。不过,因为LGWR进程将所有数据块的所有变更都写至日志文件,因此日志文件中也将存在重新构建撤销段所需的足够信息,从而能够回滚Joo未提交的事务。
综上所述,因为LGWR进程总是先于DBWn进程进行写操作,并且在提交的同时进行实时的写操作,所以在重做流中始终存在足够的信息,从而能够重新构建任何已提交的未被写入数据文件的变更,回滚任何已被写入数据文件的未提交变更。只要没有受到物理损坏,重做与回滚这种实例恢复机制就能够使Oracle数据库绝对不被破坏。
执行SHUTDOWN ABORT命令会损坏数据库吗?答案是绝对不会!这个命令不可能损坏数据库。只要联机日志文件可用,实例恢复机制就总是可以恢复任何损坏的数据。
检查点和重做日志
检查点机制
检查点位置(崩溃后,重做流中的实例恢复起点)由DBWn自动前移。这个过程称为“增量检查点(incremental checkpointing)”。除此之外,还有“完整检查点(full checkpointing)”和“局部检查点(partial checkpointing)”。
增量检查点是正常数据库活动的一部分。DBWn进程决定缓存中是否有足够的、已更新的块,是否应把其中的几个写入磁盘。选择写入哪些变更的缓冲区的算法,是基于更改时多久以前进行的,以及如何激活缓冲区。
在一般情况下,只有缓冲区已更改,且是空闲的,才能写入该缓冲区。永远不要忘记,提交变更和把块写入磁盘之前没有相关性,DBWn只写入所需的最少块数。