none
在灾难恢复过程中(crash recovery),SQL SEVER 回滚(roll back)的内部机制是什么?(全完恢复模式,事务日志备份的情况下) RRS feed

  • 问题

  • 我们知道,在灾难恢复过程中(crash recovery),SQL SEVER  前滚(roll forward)的内部机制是首先执行还原上次备份的操作(如全备份),然后根据全备份之后的事务日志中的记录(如SQL 操作记录,update,delete,insert.....),做REDO操作,

    那roll back的机制是什么呢?总不能进行相反方向的SQL 操作吧?

     举个例子,一个transaction对一个table1进行了update 操作,并且经历了一个check point ,那相应的dirty page被写入磁盘,
    但是在transaction committed之前发生了crash recovery,所以这个操作必须被rollback,
    那这个rollback的具体过程是什么样子的,也就是说如何撤销已经被写入磁盘的dirty page?

    2011年3月7日 6:55

答案

  • For those update transaction, sql logs original data and new data. You'll see that with log explorer tools.

    Hi rmiao,谢谢。
    • 已标记为答案 Jacky_shen 2012年2月20日 7:28
    2012年2月17日 1:07
  • Hi,已经收到回复了,如下:

    “您的描述是正确的。为了更加直观化,我们可以用一些日志工具如ApexSQL Log (http://www.apexsql.com/ ) 可以下载来观察一下日志的结构。

    我们创建一个测试表TESTTABLE, 并且插入如下两行数据:

    insert into TESTTABLE values (1, 'aaaa')

    insert into TESTTABLE values (2, 'bbbb')

    然后做如下的操作。

    update TESTTABLE set myName = 'cccc' where myID = 2

    这时候,我们可以看到,update的语句包含了oldValuenewValue,所以,在做rollback的时候,因为有了oldValue,所以所谓的恢复就是把value改回为oldValue即可

    同时,我们也可以看到相应的UNDO Script


    • 已标记为答案 Jacky_shen 2012年2月20日 7:28
    • 取消答案标记 Jacky_shen 2012年2月20日 8:19
    • 已编辑 Jacky_shen 2012年2月20日 8:21
    • 已标记为答案 Jacky_shen 2012年2月20日 8:22
    2012年2月20日 7:07

全部回复

  • 就是undo了,没有committed的事务就会rollback。committed的事务,但是没有写入数据文件的,会做redo。
    想不想时已是想,不如不想都不想。
    2011年3月7日 10:35
    版主
  • 就是undo了,没有committed的事务就会rollback。committed的事务,但是没有写入数据文件的,会做redo。
    想不想时已是想,不如不想都不想。
    谢谢,但是你的回答并不是我要的答案。 我问的是 通过什么方式来执行 roll back的, 举个例子,一个transaction对一个table1进行了update 操作,并且经历了一个check point ,那相应的dirty page被写入磁盘, 但是在transaction committed之前发生了crash recovery,所以这个操作必须被rollback, 那这个rollback的具体过程是什么样子的,也就是说存储引擎用什么机制来撤销已经被写入磁盘的dirty page?
    2011年3月7日 12:18
  • For uncommitted transactions, checkpoint just writes dirty pages to log. You can find details in Paul Randal's blog site http://www.sqlskills.com/blogs/paul/.
    • 已标记为答案 Jacky_shen 2011年3月7日 14:34
    • 取消答案标记 Jacky_shen 2012年2月16日 1:24
    • 已标记为答案 Jacky_shen 2012年2月16日 1:25
    • 取消答案标记 Jacky_shen 2012年2月16日 1:32
    • 已标记为答案 Jacky_shen 2012年2月16日 1:37
    • 取消答案标记 Jacky_shen 2012年2月16日 1:46
    2011年3月7日 14:29
  • Check underlined words: All dirty data file pages for the database are written to disk (all pages that have changed in memory since they were read from disk or since the last checkpoint), regardless of the state of the transaction that made the change.

     
    2012年2月16日 4:10
  • 就是undo了,没有committed的事务就会rollback。committed的事务,但是没有写入数据文件的,会做redo。


    想不想时已是想,不如不想都不想。

    谢谢,但是你的回答并不是我要的答案。 我问的是 通过什么方式来执行 roll back的, 举个例子,一个transaction对一个table1进行了update 操作,并且经历了一个check point ,那相应的dirty page被写入磁盘, 但是在transaction committed之前发生了crash recovery,所以这个操作必须被rollback, 那这个rollback的具体过程是什么样子的,也就是说存储引擎用什么机制来撤销已经被写入磁盘的dirty page?

    没看明白你的意思,一个transaction对一个表update,之后checkpoint,如果此时crash,比如断电:
    如果启动后,log文件正常,会发现一个transaction的记录,并且没有显示的commit/rollback,就会rollback,把之前那个写入到数据文件里page读到内存还原成原数据并再次经checkpoint写入数据文件
    如果启动后,log文件损坏,那之前这个transaction已经写入到数据文件里的dirtypage就会一直存在数据文件里,被认为已经正常commit.


    Best Regards, nicofer



    • 已编辑 nicofer 2012年2月16日 8:59
    2012年2月16日 8:55
  • OK, 这个我看到了,但不知道这个“written to disk” 是不是就是指written to log file on the Disk?

    你说:“For uncommitted transactions, checkpoint just writes dirty pages to log”

    我不知道你说的那句话是不是指对于uncommitted 的事务,在checkpoint 的时候只把dirty pages写入 log file ,但不会把dirty pages写入data File?

    如果这样的话,我觉得就不可能有在crash recovery的时候因为事务日志的损坏而导致数据的inconsistent了的情况了,因为对于uncommitted 的事务,如果在checkpoint 的时候,它并没有把dirty pages写入data File,这样就没有必要做UNDO了嘛(因为 data File的文件并不脏啊),就算日志坏了,它的数据还是事务之前的状态,还是一致的。


    2012年2月16日 10:33
  • 我觉得checkpoint跟crash recovery 应该是这样的一个过程,不知道对不对,请高手指点,我举个例子,

    创建如下脚本,并且插入3条数据

    CREATE TABLE [dbo].[tableA](
     [C1] [nchar](10) NULL
    ) ON [PRIMARY]

    INSERT INTO [dbo].[TableA] VALUES('A')
    INSERT INTO [dbo].[TableA] VALUES('B')
    INSERT INTO [dbo].[TableA] VALUES('C')

    此时在data File中有如下一个页面,我们称它为original page A吧

    然后开始如下的一个transaction

    Step1,begin transaction
    Step2,update tableA set C1='D'
    Step3,checkpoint happened (this is last checkpoint before system crashed)
    Step4,system crash happened

    上面的Step2之后,在buffer pool的页面的状态如下,没错吧,我称它为 dirty page A吧,

    另外,Step2我认为它除了在buffer pool中把上面的original page A改为下面状态的页面之外,还做了两件事(个人猜测),

    1,生成一个log record,假设它的LSN为002,

    2,保留一份original page A。那为什么需要保留original page A?因为这样UNDO的时候可以直接用保留的original page A覆盖掉下面的dirty page A,从而恢复数据的状态到transaction 之前,使数据一致。

    STEP 3

    然后,进入STEP 3,手动的checkpoint,它会如下3件事(个人猜测)

    1,请求log buffer manager 把LSN为002的那个日志记录写入transaction log File

    2,请求log buffer manager 把step2保留的那个original page A也写入transaction log File,以备在crash recovery UNDO阶段的时候覆盖掉脏页。

    3,把buffer pool 中的dirty page A写入 data File.

    step4

    然后,进入step4,在事务commit之前 系统崩溃了。

    然后重启,进入了crash recovery 阶段。

    crash recovery 阶段经历3个主要阶段

    1,分析,

    2,REDO

    从最老事务日志开始分析,在我们的例子中,最老事务日志应该是LSN等于002的那条,发现此日志的LSN等于buffer  pool中page 的LSN(都为002)(假设data File 中的dirty page A已经从data File中取出来,并且放入了buffer  pool)

    3,UNDO

    从阶段1分析出次transaction没有commit,所以对次transaction进行UNDO操作,从跟REDO相反的方向开始做。对LSN为002的日志做UNDO,由于事务日志记录中有一个original page A,所以此UNDO 操作直接用original page A覆盖掉 buffer pool中的dirty page A,至此,数据恢复完毕,数据也已经恢复为transaction 开始之前的状态,从而保证了数据的一致性。

    也就是数据的UNDO操作是用原始的页面来覆盖掉脏页来现实的,对把?

    这就是我以上的分析,不知道对不对,请高手指点指点,谢谢:-)

    2012年2月16日 10:56
  • OK, 这个我看到了,但不知道这个“written to disk” 是不是就是指written to log file on the Disk?

    你说:“For uncommitted transactions, checkpoint just writes dirty pages to log”

    我不知道你说的那句话是不是指对于uncommitted 的事务,在checkpoint 的时候只把dirty pages写入 log file ,但不会把dirty pages写入data File?

    如果这样的话,我觉得就不可能有在crash recovery的时候因为事务日志的损坏而导致数据的inconsistent了的情况了,因为对于uncommitted 的事务,如果在checkpoint 的时候,它并没有把dirty pages写入data File,这样就没有必要做UNDO了嘛(因为 data File的文件并不脏啊),就算日志坏了,它的数据还是事务之前的状态,还是一致的。



    Sql writes dirty pages to data file on disk and writes related transactions to log file that's on disk as well.
    2012年2月16日 15:30
  • Sql doesn't keep original page as before image unless you enabled row versioning, doesn't keep data pages in log either if db is in full recovery mode. It uses tranaction log to rollback in case of recovery.
    2012年2月16日 15:37
  • Sql doesn't keep original page as before image unless you enabled row versioning, doesn't keep data pages in log either if db is in full recovery mode. It uses tranaction log to rollback in case of recovery.

    非常感谢RMIAO,

    如果没有保持original page 的话,那SQL SERVER在做UNDO操作的时候是如何把脏页中的D,D,D三条记录分别ROLLBACK为A,B,C?

    难道是对三条记录分别执行如下的操作?

    update tableA set C1='A' WHERE XXX=第一条记录的地址

    update tableA set C1='B' WHERE XXX=第二条记录的地址

    update tableA set C1='C' WHERE XXX=第三条记录的地址

    2012年2月16日 15:45
  • For those update transaction, sql logs original data and new data. You'll see that with log explorer tools.
    2012年2月16日 17:36
  • 我觉得checkpoint跟crash recovery 应该是这样的一个过程,不知道对不对,请高手指点,我举个例子,

    创建如下脚本,并且插入3条数据

    CREATE TABLE [dbo].[tableA](
     [C1] [nchar](10) NULL
    ) ON [PRIMARY]

    INSERT INTO [dbo].[TableA] VALUES('A')
    INSERT INTO [dbo].[TableA] VALUES('B')
    INSERT INTO [dbo].[TableA] VALUES('C')

    此时在data File中有如下一个页面,我们称它为original page A吧

    然后开始如下的一个transaction

    Step1,begin transaction
    Step2,update tableA set C1='D'
    Step3,checkpoint happened (this is last checkpoint before system crashed)
    Step4,system crash happened

    上面的Step2之后,在buffer pool的页面的状态如下,没错吧,我称它为 dirty page A吧,

    另外,Step2我认为它除了在buffer pool中把上面的original page A改为下面状态的页面之外,还做了两件事(个人猜测),

    1,生成一个log record,假设它的LSN为002,

    2,保留一份original page A。那为什么需要保留original page A?因为这样UNDO的时候可以直接用保留的original page A覆盖掉下面的dirty page A,从而恢复数据的状态到transaction 之前,使数据一致。

    STEP 3

    然后,进入STEP 3,手动的checkpoint,它会如下3件事(个人猜测)

    1,请求log buffer manager 把LSN为002的那个日志记录写入transaction log File

    2,请求log buffer manager 把step2保留的那个original page A也写入transaction log File,以备在crash recovery UNDO阶段的时候覆盖掉脏页。

    3,把buffer page中的dirty page A写入 data File.

    step4

    然后,进入step4,在事务commit之前 系统崩溃了。

    然后重启,进入了crash recovery 阶段。

    crash recovery 阶段经历3个主要阶段

    1,分析,

    2,REDO

    从最老事务日志开始分析,在我们的例子中,最老事务日志应该是LSN等于002的那条,发现次日志的LSN等于buffer  pool中page(,(假设data File 中的dirty page A已经从data File中取出来,并且放入了buffer  pool)) 中的LSN(都为002),所以针对次LOG 记录不需要做REDO

    3,UNDO

    从阶段1分析出次transaction没有commit,所以对次transaction进行UNDO操作,从跟REDO相反的方向开始做。对LSN为002的日志做UNDO,由于事务日志中记录中有一个original page A,所以次UNDO 操作直接用original page A覆盖掉 buffer pool中的dirty page A,至此,数据恢复完毕,数据也已经恢复为transaction 开始之前的状态,从而保证了数据的一致性。

    也就是数据的UNDO操作是用原始的页面来覆盖掉脏页来现实的,对把?

    这就是我以上的分析,不知道对不对,请高手指点指点,谢谢:-)



    Hi jacky, 我个人认为你描述的正确。如果想确认准备性,可以mail给亚太支持组:
    http://blogs.msdn.com/b/apgcdsd/contact.aspx
    留下你的email,一般都会有人回复:D
    等待你的结果

    Best Regards, nicofer

    2012年2月17日 0:43
  • For those update transaction, sql logs original data and new data. You'll see that with log explorer tools.

    Hi rmiao,谢谢。
    • 已标记为答案 Jacky_shen 2012年2月20日 7:28
    2012年2月17日 1:07
  • Hi nicofer,

    谢谢提醒。

    2012年2月17日 1:07
  • Hi,已经收到回复了,如下:

    “您的描述是正确的。为了更加直观化,我们可以用一些日志工具如ApexSQL Log (http://www.apexsql.com/ ) 可以下载来观察一下日志的结构。

    我们创建一个测试表TESTTABLE, 并且插入如下两行数据:

    insert into TESTTABLE values (1, 'aaaa')

    insert into TESTTABLE values (2, 'bbbb')

    然后做如下的操作。

    update TESTTABLE set myName = 'cccc' where myID = 2

    这时候,我们可以看到,update的语句包含了oldValuenewValue,所以,在做rollback的时候,因为有了oldValue,所以所谓的恢复就是把value改回为oldValue即可

    同时,我们也可以看到相应的UNDO Script


    • 已标记为答案 Jacky_shen 2012年2月20日 7:28
    • 取消答案标记 Jacky_shen 2012年2月20日 8:19
    • 已编辑 Jacky_shen 2012年2月20日 8:21
    • 已标记为答案 Jacky_shen 2012年2月20日 8:22
    2012年2月20日 7:07
  • REDO script:

    "

    顺便说一下,RMIAO的说法是正确的。只是记录oldValue和newValue,而不是记录那个值对应的整个oldpage跟newpage。



    2012年2月20日 7:08
  • hi jacky , thanks for sharing !!!

    Best Regards, nicofer

    2012年2月21日 1:44