数据库系统中恢复是指让数据库从发生某些“失败”后的不一致的状态恢复到正常的一致状态的行为,恢复的基础是冗余(物理上冗余,非逻辑上)
这些失败包括了:
大体上,恢复策略分成两个步骤:
本小节假设讨论恢复问题时的存储结构和数据访问模型
按系统奔溃时是否影响数据存储,将存储器分成易失存储器(主存、cache等)和非易失存储器(磁盘磁带、闪存、非易失RAM等),然后我们假设一种理想的稳定存储器(stable storage),发生任何失败时都不会影响存储数据内容
定义物理块为存储在非易失的磁盘上的块,缓冲块是为存储在易失的主存中的块,而私有空间是指为每个事务T分配的独立于其他事务的虚拟存储区域,那么可以命名一下4种操作:
假设在事务中,DBMS在第一次访问块X时调用一次read操作加载到私有缓冲区,事务执行完毕时write(X)写回主存,而事务中间的操作时都只是修改其本地副本
注意,DBMS没有必要在每次write时调用output,这取决于OS的写回策略
日志是一组记录在理想的稳定存储器上的数据库存储记录,约定:
<Ti, start>
<Ti, X, old_value, new_value>
<Ti, commit>
基于日志的恢复有两种策略,推迟数据库修改和立即数据库修改
推迟数据库修改模式下,数据库的修改操作仅记录在Log中而不真正的实施write操作,直到partial committed之后才write
定义在失败发生时的redo和undo操作:
<Ti, X, old_value, new_value>
再一次写入新值new_value<Ti, X, old_value, new_value>
撤销新值写入,即写入old_value由推迟数据库修改模式的定义知,未记录<Ti, commit>
的事务不执行任何恢复操作,已记录<Ti, commit>
的事务顺序地执行redo操作(其实这种模式下old_value是没有必要记录的)
立即数据库修改模式和推迟数据库修改模式相反,事务未commit之前就允许修改数据库,write-ahead logging rule(WAL规则)规定log记录必须在数据库写入之前完成
立即数据库修改下,未记录<Ti, commit>
的事务必须反序地执行undo操作让数据库返回到一致性状态,而已记录<Ti, commit>
的事务顺序地执行redo操作
每次redo和undo时都遍历整个Log并完成所有事务的redo和undo的话,开销十分巨大,并且对于已经commit后output写入磁盘的redo是没有任何意义的,因此在Log引入<checkpoint>
语句
DBMS周期性地做检查工作,把所有commit的事务(已write入主存)从主存中写回到磁盘中,并在日志中记录一条<checkpoint>
;注意检查时,可能某个事务还未commit
有了检查点的数据库恢复,每次错误时只需恢复最近的事务即可:
<checkpoint>
<Ti, start>
那么对于下面的时序图,发生失败时有(立即数据库修改模式):
除了基于日志的恢复,还另一种恢复策略——影子数据库(Shadow Database),它有以下设定
影子数据库的拷贝策略运用在大型数据库上十分低效
13.3中介绍的基于Log的恢复是针对单活跃事务而言的,下面进行更多的假设已完成对并发事务的恢复:
<checkpoint, L>
,L是检查点发生时活跃的事务列表undo_list
和redo_list
为空表,倒序找到第一个<checkpoint, L>
,对于L中每一个事务的update按Log记录反序加入undo_list
、正序加入redo_list
undo_list
和redo_list
中的操作如果把Log缓存在主存中,那么当缓存已满或log force操作时才把Log记录(全部)写入磁盘(这样多条log记录可以一次output,减少I/O开销),此外Log记录缓存还必须遵从以下约定:
<Ti, commit>
写入磁盘后才能进入Committed状态数据库缓存和Log记录缓存不一样的是,它是分块划分缓存的,当缓存满时是选择缓存块被新块替换(若修改需要写回磁盘),而不整个缓存写回
上述对恢复的讨论仅包含易失存储器的部分,非易失存储器的恢复也利用了相似的分层存储器思想:增加一种dump
操作,它下一级是理想的稳定存储器(可以假想为磁带等层次更低的存储介质)
原文地址:http://blog.csdn.net/u014030117/article/details/46674469