登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

飞哥的技术博客

世上无难事,只怕有心人!

 
 
 

日志

 
 
 
 

oracle编程艺术第9章-UNDO和REDO读书笔记  

2009-06-23 20:37:33|  分类: Oracle |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 oracle编程艺术第9章-UNDO和REDO读书笔记

弄懂几个概念:

redo是重做日志文件,是oracle数据库的日志文件.oracle的重做日志有两种:在线重做日志以及归档重做日志。

在线重做日志:主要用于由于数据库主机掉电等原因导致实例失败,此时oracle采用在线重做日志在数据库启动时将数据库恢复到

归档重做日志:主要用于介质失败,比如:磁盘受损。此时需要使用对磁盘上的数据备份的归动重做日志文件将该磁盘上的数据恢

              复到该归档文件数据所在的时间点上,然后再使用在线重做日志文件将适合的时间点上。

归档重做日志文件实质是被添满的旧的在线重做日志的副本。归档重做日志文件是数据库的历史数据。

在线重做日志在每个数据库中至少有两个重做日志组,每个日志组中至少有一个重做日志文件,这些在线重做日志组是循环使用的,

当日志组1被写到最后时,然后自动切换到日志组2;当日志组2也被写满时,再切换到日志组1。

undo与redo相反,redo是恢复数据,用于在事务失败时重放事务,undo是撤消一条语句或者一组语句的作用。undo是存储在数据库内部的

段或者表空间中(undo如果是手动管理,则使用undo段来管理;如果undo使用AUM管理UNDO,则undo使用表空间来自动管理)。

注意:在undo并不是物理的恢复到执行语句之前或者事务之前的样子,只是逻辑的恢复到原来的样子,所有修改只是逻辑的取消,但是数

据结构和数据块在回滚之后也大不相同。原因是在多用户系统中,有很多事务是并发进行的,当一个事务修改一个数据并且被回滚,

      但是该数据在该用户对该数据做过修改之后也也有被其他用户修改,这个时候如果是对该事务修改的数据块回滚到原来数据的物理

      样子,就有可能将后来的事务所做的修改给覆盖掉。所以回滚不是一个简单的物理的恢复,而是逻辑恢复。

例如:做下面的步骤:

SQL> drop table t;

表已删除。

SQL> create table t

表已创建。

SQL> select * from t;

未选定行

SQL> set autotrace traceonly statistics

SQL> select * from t;

未选定行

统计信息

----------------------------------------------------------

        992  bytes sent via SQL*Net to client

        374  bytes received via SQL*Net from client

     1  SQL*Net roundtrips to/from client

SQL> set autotrace off;

注意:在每个用例做2次全表扫描,这样是为了避免解析和优化期间优化器可能产生的额外的I/O,测试只需要比较第二次的查询情况

    

SQL> insert into t select * from all_objects;

统计信息

-----------------------------------------------------

        676  bytes sent via SQL*Net to client

        575  bytes received via SQL*Net from client

          4  SQL*Net roundtrips to/from client

SQL> rollback;

回退已完成。

SQL> select * from t;

未选定行

SQL> set autotrace traceonly statistics

SQL> select * from t;

未选定行

统计信息

----------------------------------------------------------

        992  bytes sent via SQL*Net to client

        374  bytes received via SQL*Net from client

          1  SQL*Net roundtrips to/from client

SQL> set autotrace off;

分析:在进行插入操作的时候数据库为该表分配可新的数据块,表示表所占用的空间变大。进行插入操作,表得到新的数据块,然后格式

      化新的数据块,然后准备放数据进入;此时另一个事务是回滚这些数据,此时回滚并不能将新分配给表的空间给撤消掉,也不能取消

      对数据块的格式化操作,实际做的是与原来的逻辑相反的工作,insert操作相反的操作是delete,delete相反的操作是insert操作,

操作相反的操作是另外执行一个update操作将其变为原来的行。

     

undo信息是存放在UNDO表空间或者UNDO段中,也会受REDO保护,即表示会将UNDO数据当做表数据或者是索引数据一样,对UNDO的修改也会

产生一些REDO,这些REDO信息也会被记录到日志中去。为什么会这样?在下面讲解系统崩溃发生的情况会解释。undo数据会被加到UNDO段

有下面的三句语句:

insert into t(x,y)values(1,1);

update t set x=x+1 where x=1;

delete from t where x=2;

假设沿着不同的路径完成这个事务,得到不同的答案:

路径1:如果系统在处理这些语句的不同时间点上失败,会发生什么情况;

对于第一条语句进行的insert into语句,redo和undo都会生成。所生成的UNDO足以撤消insert操作的作用;所生成的REDO可以使这个插入操作再次复现;

oracle编程艺术第9章-UNDO和REDO读书笔记 - daimins BLOG - CSDN博客 - yangzhongfei - 中飞博客

图中显示了缓存中存放的已经被修改的UNDO块,索引块和表数据块,这些数据块都得到了重做日志缓冲区中相应的redo项保存;

系统现在崩溃没有关系。SGA会被清空,但是SGA中的内容我们并不需要。因为在系统重新启动时就好象这个事务没有发生过一样。没有任何已修改的块刷新输出到磁盘,也没有任何REDO刷新输出到磁盘,这样就不需要这些undo和redo信息来实现实例恢复;

由于缓存区已满,所以DBWR进程需要将已修改的数据块从缓存中刷新写入磁盘中去来留出空闲的空间。如果是这样,DBWR首先是要求LGWR进程将这些已被修改的数据块的相关的REDO条目信息先刷新写入重做日志文件中去。DBWR在做任何将已被修改的数据块写进磁盘中之前,都要做首先通知LGWR进程先将这些块相关的REDO信息写入重做日志文件中去。假设没有这样的话,在DBWR将被修改的数据块写进磁盘之前没有通知LGWR进程将REDO信息写进重做日志文件,一旦系统失败的话,就只有被修改的数据,而没有与之相关的REDO信息而造成系统不能很好的恢复。但是如果进行了通知LGWR进程先将这些块相关的REDO信息写入重做日志文件中去的话,这样就能够重做所有的修改,将SGA恢复到系统失败前的状态,从而可以成功回滚。

从图1中可以看出,生成的被修改的书数据块和索引块,以及与这些被修改的数据块相关的UNDO段块,这三部分都会生成REDO来保护自己的。

重做日志缓冲区刷新输出的条件:

每3秒一次;缓冲区达到1/3满时;或者包含1M的缓冲数据;或者是只要发生事务提交就会发生刷新输出;重做日志缓冲区很有可能会在处理期间的某个时间点上刷新输出,并且刷新输出的状态是如图2:

oracle编程艺术第9章-UNDO和REDO读书笔记 - daimins BLOG - CSDN博客 - yangzhongfei - 中飞博客

Update所带来的工作和Insert大体一样。不过Update生成的undo量更大;由于是更新,需要保存更新前的数据,即“前”映象。

oracle编程艺术第9章-UNDO和REDO读书笔记 - daimins BLOG - CSDN博客 - yangzhongfei - 中飞博客

块缓冲区中会有更多新的UNDO块,为了也能够撤消这个更新,如果有必要,已修改的数据库整张表和索引块也会放到缓存中,也会生成更多的重做日志缓冲区条目。下面假设前面的插入语句生成了一些重做日志,有部分被写进重做日志文件中,但是还有一些仍存放在缓存中。

该场景涵盖了系统崩溃恢复的基本细节。系统将其作为一个2步的过程来完成。首先前滚,将系统放到失败的点上,然后回滚尚未提交的所有工作,这个动作会再次同步数据文件。它会重放已经进行的工作,并撤消尚未完成的所有工作。

第一步:前滚,将系统放到失败的时间点上:

系统启动时,系统会读取重做日志,发现有相关的事务的一些重做日志条目。给定系统的当前状态,利用重做日志文件中对应插入的REDO条目,还有仍在缓冲区中的一些对应的REDO信息,oracle会前滚插入;(前面讲系统崩溃,SGA被清空,那么在这里应该也会清空缓冲区中的REDO信息的呀?但是为什么还仍然继续存在?这里的缓冲区不在SGA中吗?)前滚得到图1中的状态。

第二步:如果发现前面的插入操作还没有提交,并且这个插入语句对应的UNDO块(用于撤消插入),已修改的表块(刚插入后的状态),以及已修改的索引块(刚插入后的状态),此时系统会使用上面的这些UNDO信息来回滚。系统取刚刚在缓冲区缓存中前滚得到的UNDO,并将这些UNDO应用到数据块和索引块,使数据块和索引块恢复到插入前的系统状态。这样回到插入前的状态,但是在磁盘上的块可能会反映插入后的数据,也可能不反映(这个取决于崩溃前DBWR是否进行块刷新输出将数据写进磁盘)。如果磁盘中的块确实反映了插入,而实际上插入已经被撤消。此时这个只有在当缓冲区缓存刷新输出块时,数据文件就会被重新写,使得数据文件反映出插入已撤消。如果磁盘上的块没有反映前面的插入,就不用管它-这些块以后会被覆盖。

假设场景:应用回滚事务

Oracle发现这个事务的UNDO信息可能在缓存的UNDO段中块中(基本上这样),也可能这个事物的UNDO信息已经被刷新写进磁盘中去(当大事务会有这种情况发生)。系统会将UNDO信息应用到缓冲区缓存中的数据块和索引块上,或者如果这些需要回滚的数据块已经不在缓存中,则就需要从磁盘中将对应的数据和索引块读入缓存,再对其进行应用UNDO。这些块会恢复为原来的行值,并刷新输出到数据文件写进磁盘中去。

需要指出一点:回滚过程不涉及对重做日志,只有在恢复和归档时才会读取重做日志。Oracle在正常情况下,不会重做日志进行读取操作。Oracle的目标是:可以顺序地写日志,而且在写日志时别人不会读日志,这样主要是为了提高性能和避免资源竞争。

DELETE会生成UNDO,块被修改,并且将REDO写到重做日志缓冲区中。这个与前面的UPDATE差不多。

COMMIT,此时oracle会将日志缓冲区刷新输出到磁盘中去。如图4:

oracle编程艺术第9章-UNDO和REDO读书笔记 - daimins BLOG - CSDN博客 - yangzhongfei - 中飞博客

已修改的数据块或者还在缓冲区缓存中;也有可能被写进磁盘中去。但是重做这个事务的所有REDO信息都被写进磁盘中去,此时就表示这个数据的修改是永久的了。如果有读取文件中的数据不是事务发生之后的样子,这个是由于DBWR还没有立即写进磁盘的原因,这个不要紧。如果出现读取失败,可以通过重做日志文件来得到最新的块信息。UNDO信息也存在(除非UNDO被重用),UNDO信息存在就可以保证数据的一致性,可以回滚到过去某个时间点上的数据。

COMMIT操作是一个很快的操作,并且每个COMMIT操作其响应的时间或多或少是平均的,不管事务的大小。

取决于前三项的大小,以及这些花费的时间,前面的某个数据(或者是某些数据)被刷新 写入磁盘;

*LGWR将所有余下的缓存重做日志条目写到磁盘中,并将SCN记录到在线虫做日志文件中,这步的完成表示事务提交的真正完成。此时,事务条目会从V$TRANSACTION视图中删除掉,表示事务已经提交;

*如果事务修改的数据块还有部分还没有写入磁盘,则会一种快速的模式访问并“清理“。块清理(block cleanout)是指清除存储在数据库首部的与锁相关的信息。实质是清除块上的事务信息。这样下一个访问这个块的人就不用再做块清理了操作了。这种是采用一种无需生成重做日志信息的方式来完成块清除。

由上可以看出,处理CMMIT操作所要的做的工作很少,耗时最长的是LGWR执行的将REDO写进磁盘的操作,因为这个操作进行了物理磁盘I/O。但是CMMIT又是很快的原因是在于LGWR在你的工作期间一直在以连续的方式将重做日志缓冲区的内容写进磁盘中,同时LGWR也一直在以增量的方式来不停的刷新重做日志缓冲区中的内容。这样避免一次性将大量REDO写进磁盘操作使提交等待很长时间。

Rollback与commit相反,它是一个与被修改的数据量有关的一个函数。被修改的数据量越大,rollback所需要的时间越长。

取决于前三项的大小,以及这些花费的时间,前面的某个数据(或者是某些数据)被刷新 写入磁盘;

*撤消已做的所有修改。其完成方式如下:从UNDO中读回数据,然后逆向执行前面所做的操作,并且将UNDO条目记为已用。如果先前是插入,rollback会将删除,如果是更新了一行,则回滚就撤消这个更新操作;如果是删除了一行,则回滚就需要插入一行。

  评论这张
 
阅读(913)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018