当前位置: 首页 > 科技观察

关于Oracle实例恢复的前滚和回滚的理解

时间:2023-03-17 18:57:34 科技观察

一直以来对oracle实例恢复的一些理解存在误区。今天通过查阅相关资料,和同学一起讨论,发现了自己的错误。讨论结果如下:实例恢复:当数据库异常关闭时(断电或shuabort等不一致关机),当你重启数据库时,数据库相关进程会自动恢复实例,无需人工干预。当实例需要恢复到shutdownnormal或者shutdownimmediate,也就是所谓的cleanshutdown时,会自动触发checkpoint,并回写SCN记录。当一个checkpoint发生时,SCN会被写入四个地方:控制文件中的三个地方:SYSTEMCHECKPOINTSCNDatafilecheckpointSCNStopSCN:关闭实例一致性时,更新datafileheader中的一个:1.StartForaconsistentdatabase在SCN正常打开状态下,SYSTEMCHECKPOINTSCN、DatafilecheckpointSCN和数据文件头StartSCN这三个SCN是一致的,控制文件中存储的stopscn会返回NULL值。cleanshutdown时,会进行checkpoint,此时数据文件的stopscn和控制文件中的startscn相同。数据库打开时,Oracle会检查数据文件头中的startscn和控制文件中存放的datafile的scn是否相同,如果相同,则检查startscn和stopscn是否相同,如果还是一样,则正常打开数据库,否则需要恢复。数据库打开后,控制文件中保存的stopscn会返回NULL值,表示数据文件以普通模式打开。异常关机如果异常SHUTDOWN(shutdownabort),挂载数据库后,会发现stopscn不等于其他位置的scn,而是等于NULL,说明oracle在shutdown时没有做checkpoint,必须崩溃下次恢复(实例恢复)。注意:在启动数据库时,如果发现STOPSCN=NULL,说明需要进行崩溃恢复;启动数据库时,如果发现数据文件头的STARTSCN不等于CONTROLFILE中存储的DATAFILESCN,说明需要进行Mediarecovery2.Instancerecovery具体过程当数据库突然crash时,以及buffercache中的脏数据块没有及时刷新到数据文件,正在运行的事务在实例崩溃时突然中断,事务处于中间状态,即还没有提交。也没有回滚。此时数据文件中的内容无法反映实例崩溃时的状态。这样关闭的数据库是不一致的。下次启动实例时,Oracle会通过SMON进程自动恢复实例。实例启动时,SMON进程会检查控制文件中记录的每个在线的、可读写的数据文件的ENDSCN号。在数据库正常运行期间,ENDSCN号总是NULL。当数据库正常关闭时,将执行一次全检查点,并更新该字段中的检查点SCN号。所以可以通过ENDSCN号是否为空来判断。需要实例恢复。当崩溃发生时,Oracle还没有来得及更新该字段,所以该字段仍然是NULL。当SMON进程发现这个字段为空时,就知道上次实例没有正常关闭,于是SMON进程开始恢复实例。SMON进程在恢复实例时,会从控制文件中获取checkpoint位置。于是,SMON进程在在线日志文件中找到checkpoint位置,然后应用从checkpoint位置往下的所有redoentry,从而在buffercache中恢复实例崩溃时的状态。此过程称为前滚。roll-forward完成后,buffercache中有crash时已经提交但没有写入数据文件的脏数据块,也有突然终止的事务,导致既没有commit也没有rollback的数据块脏交易。前滚完成后,SMON进程立即打开数据库。但是此时的数据库中仍然包含着那些既没有提交也没有回滚的处于中间状态的脏块。这样的脏块在数据库中是不可能存在的,因为它们还没有提交,必须要回滚。打开数据库后,SMON进程会在后台回滚。有时,数据库打开后,SMON进程还来不及回滚这些中间状态的数据块,用户进程就发出了读取这些数据块的请求。此时,在服务器进程将这些块返回给用户之前,服务器进程负责回滚。回滚完成后,将数据块的内容返回给用户。3、为什么数据库实例恢复回滚再回滚?回滚段实际上以回滚表空间的形式存在。既然是表空间,就一定有对应的数据文件。同时,它会在buffercache中存在Imageblocks,就像其他表空间的数据文件一样。当发生DML操作时,必须同时产生REDO(用于DML操作本身的REDOEntry)和UNDO(用于回滚DML操作,记录在UNDO表空间中),但是由于UNDO信息也使用回滚表空间来store,则DML操作对应的UNDO信息(对应BUFFERCACHE生成中的UNDOBLOCK)会先生成其对应的REDO信息(UNDOBLOCK的REDOEntry)写入LogBuffer。这样做的原因是BufferCache中与UNDO表空间相关的块也可能因为数据库故障而丢失。为了保证下次启动时顺利回滚,必须先使用REDO日志来恢复UNDO段(实际上是先回复BufferCache中的脏数据块,再通过Checkpoint写入UNDO段),然后在数据库OPEN后利用UNDO信息回滚,达到一致性的目的。UNDOBLOCK的REDOEntry生成后,轮到DML语句对应的REDOEntry,最后修改BufferCache中的Block,同时Block变成脏数据块。其实简单来说,REDO的作用就是记录所有的数据库变化,包括UNDO表空间。今天总结最重要的一点,我知道所谓的rollforward就是应用redo来恢复buffercache数据,将buffercache恢复到crash前的状态,所以这个时候buffercache已经崩溃的时候已经提交了,但是还没有写入。数据文件的脏数据块,以及由于事务突然终止(即没有commit,但是dbwr已经flush了底层的修改)导致既没有提交也没有回滚的事务的脏数据块disk),还有一点就是在控制文件中还有一个endscn,用来记录数据库正常关闭时数据库文件头的scn,通过scn是否为null可以判断是否正常关闭不恢复实例。