• redo/undo


    一、什么是redo?

    redo:oracle在在线或者归档重做日志文件中的记录的信息,外以出现失败时可以利用这些数据来"重放"事务。
    每个oracle数据都至少有二个在线重做日志组,每个组中的至少有一个成员,这些在线重做日志组以循环方式使用。
    二、什么是undo?
    undo:oracle在undo段中记录的信息,用于取消或者回滚事务。
    undo在数据库内部存储在一组特殊的段中,称作undo段。
    利用undo段恢复数据,不是将数据库物理地恢复到执行语句或者事务之前的样子,只是从逻辑上恢复到原来的样子,但是数据结构以及数据库块本身在回滚后可能大不相同。oracle在回滚时候,它实际上会做与先前逻辑上相反的工作,对于每个insert,oracle会完成一个delete,对于每个delete,oracle会执行一个insert,对于每个update,oracle则会执行一个"反update",或者执行另外一个update,将修改前的行放回去。

    小实验:

    create table t as select * from all_objects where 1=0;
    select * from t;
    set autotrace traceonly statistics
    select * from t;
    insert into t select * from all_objects;
    rollback;
    select * from t;
    set autotrace traceonly statistics
    select * from t;

    三、redo和undo如何协作?

    undo信息存储在undo表空间或者undo段中,但是也会受到redo的保护。

    在dml语句中,redo和undo都会生成。update生成的undo要比insert大,因为update需要保存修改数据的"前"映像。

    系统崩溃恢复有两个过程,首先数据前滚,把系统放到失败点上,然后回滚尚未提交的所有工作。这个动作会再次同步数据文件。它会重放已经进行的工作,并撤销尚未完成的所有工作。
    oracle有一点很重要:rollback过程从不涉及到redo日志。只有恢复和归档时会读取redo日志。oracle的目标是可以顺序写redo日志,而且在写日志时别人不会读日志 。

    四、commit会做什么?
    commit通常是一个非常快的操作,而不论事务大小如何。
    这是oracle提倡用户的使用事务的提交根据业务来原因之一。commit的开销存在二个因素:
    1、增加与数据库的往返通信。
    2、每次提交时,必须等待redo写至磁盘,这会导致"等待"。在这种情况下,等待称为"log file sync".
    commit前做的工作:
    1、已经在SGA中生成了undo块。
    2、已经在SGA中生成了已经修改数据块。
    3、已经在SGA中生成了对应前二项的缓存redo。
    4、取决于前三项的大小,以及这些工作花费的时间,前面的某个数据或者某些数据可能已经刷新输出到磁盘。
    5、已经得到了所需的全部锁。
    commit时候做的工作:
    1、为事务生成一个scn。每次有人commit时,scn都会增1。
    2、lgwr将所有余下的缓存重做日志条目写至磁盘,并把scn记录到redo日志文件中。这一步是真正的commit。如果出现了这一步,即已经提交。事务条目会从v$transaction中删除,这说明我们已经提交。
    3、v$lock中记录着我们的会话持有的锁,这些锁都将被释放,而排队等待这些锁的每一个人都会唤醒,可以继续完成他们的工作。
    4、如果事务修改的某些块还在缓冲区缓存中,则会以一种快速的模式访问并"清理"。块清除是指清除存储在数据块首部的与锁相关的信息。
    五、rollback会做什么?
    rollback必须逻辑地撤销我们所做的工作,回滚时间绝对是所修改数据量的一个函数。
    rollback时候做的工作:
    1、撤销已经做的所有修改。其完成方式如下:从undo段读回数据,然后实际上逆向执行前面所做的操作,并将undo条目标记为已用。
    2、会话持有的所有锁都将释放,如果有人在排队等待我们持有的锁,就会被唤醒。
    六、分析redo
    redo管理是数据库中的一个串行点。任何oracle实例都只有一个lgwr,最终所有事务都会归于lgwr,要求这个进程管理他们的redo,并commit其事务。lgwr要做的越多,系统就会越慢。
    1、如何测量redo?
    v$mystat:会话的统计信息。
    v$statname:这个视图告诉我们v$mystat中的每一行代表什么意思。
    select b.NAME,a.VALUE from v$mystat a,v$statname b where a.STATISTIC#=b.STATISTIC# and b.name='redo size';

    七、redo生成和before/after触发器。
    1、before或者after触发器不影响delete生成的redo。
    2、oracle9i release 2以及以前版本中,before或者after触发器会使insert生成同样数量的额外redo。在oracle 10g中,则不会生成任何额外的redo。
    3、在oracle9i release 2 及以前的所有版本中,update生成的redo只受before触发器影响,after触发器不会增加任何额外的redo,不过oracle 10g中,
    如果一个表没有触发器,对其更新期间生成的redo量总是比oracle9i及以前版本中要少。看来这是oracle着力解决的一个关键问题:对于无触发器的表,要减少这种表更新所生成的redo量。
    在oracle 10g中,如果表有一个before触发器,则其更新期间生成的redo量比9i中更大。
    如果表中after触发器,则更新所生成的redo量与9i中一样。

    每个开发人员应该具备的能力:
    1、估计你的"事务"大小(需要修改数据量)。
    2、在修改的数据量基础上再增加10%-20%的开销,具体增加多大的开销取决于你的要修改的行数,修改得行数越多,增加的开销就越小。
    3、对于update,要把这个估计值加倍。八、我能关掉redo日志生成吗?
    答案:不能。
    1、在sql中设置nologging:有些sql和操作支持nologging字句,这个对象的所有操作在执行时都不生成重做日志,而是说有些特定操作生成的redo会比平常少的多。
    select * from v$database;
    --改成archivelog mode
    shutdown immediate
    startup mount
    alter database archivelog;
    alter database open;
    --改成noarchivelog mode
    shutdown immediate
    startup mount
    alter database noarchivelog;
    alter database open;
    ----------------------------------
    drop table t;
    @ 'C:\Oracle\mystat' "redo size"
    create table t as select * from all_objects;
    @ 'C:\Oracle\mystat' "redo size"
    drop table t;
    @ 'C:\Oracle\mystat' "redo size"
    create table t nologging as select * from all_objects;
    @ 'C:\Oracle\mystat' "redo size"
    在noarchiving mode的数据库中,除了数据字典的修改外,create table不会记录日志,create index/drop index生成日志。
    关于nologging操作,需要注意地方:
    虽然是nologging mode,还会生成少量的redo,这些redo作用是保护数据字典。
    nologging不能避免所有后续操作生成redo,在前面例子中,dml操作还会正常生成redo日志,sql*loader、insert /*append*/语法不生成日志。
    在一个archivelog模式的数据执行nologging操作后,必须尽快为受影响的数据文件建立一个新的基准备份,从而避免由于介质失败而丢失对这些对象的后续修改。
    2、nologing小结:
    索引的创建和alter(rebuild)。
    表的批量insert(通过/*append*/)或者采用sql*loader,表数据不生成redo。
    lob操作。
    通过create table as select 创建表。
    各种alter table 操作。
    在一个archiveing mode数据库中适当使用nologging,可以加快许多操作的速度。

    九、为什么不能分配一个新日志?
    dbwr、lgwr、arch进程操作时异步,如果dbwr还没有完成redo日志所保护数据的检查点,或者arch还没有把rdo日志文件复制到归档目标,就发生checkpoint not complete或者archival required。
    解决办法:
    1、让dbwr更快一些,可以使用async i/o、使用dbwr i/o从属进程,或者使用多个dbwr进程。这个方法好处是:宁可ibuyong付出什么代价就能有所收获,性能提高,而且不必修改如何逻辑/结构/代码。
    2、增加更多重做日志文件。这种方法:可以消除系统中的"暂停",其缺点是会消耗更多的磁盘空间。
    3、重新创建更大的日志文件。
    4、让检查点发生得更频繁,此方法很不可取。

    十、块清除。
    block cleanout:即删除所有修改数据块上与"锁定"有关的信息。
    有二个场合会做block cleanout,在commit时候,在SGA中的数据块中"锁定"信息会被清除掉,不在SGA中的数据块的将被忽略;这些被忽略的块会在第一次访问时候被清除。

    十一、日志竞争
    出现日志竞争时,数据库会提示“cannot allocate new log”。
    原因可能是:redo放在一个慢速设备上。
    redo与其他频繁访问的文件放在一个设备上。
    以缓冲方式装载日志设备。
    redo采用一个慢速技术,比如RAID-5.
    解决方法:每组的redo日志文件放在不同的磁盘上;使用快速的设备;以raw磁盘装载日志。
    十二、临时表和redo/undo
    临时表不会为它们的块生成redo。因此,对临时表的操作不是“可恢复的”,修改临时表中的一个块时,不会将这个这个修改记录到重做日志文件中,不过,临时表确实会生成undo,而这个undo会记入日志,因此,临时表也会生成一些redo。
    临时表的作用一般是insert和select为主。
    十三、分析undo
    1、dml操作生成undo情况
    一般来说,insert生成的undo最少,因为oracle为此所需要记录的只是要“delete”的一个rowid;update一般排名第二,对于update,只需记录修改的字节;delete一般生成的redo最多,对于delete,oracle必须把整行的前映像记录到undo段中。
    如何测量?
    在事务中,可以通过v$transaction.used_ublk字段察看。
    drop table t;
    create table t as select object_name unindexed,object_name indexed from all_objects ;
    create index t_inx on t(indexed);
    exec dbms_stats.gather_table_stats(user,'T');
    SELECT used_ublk from v$transaction where addr =(select taddr from v$session where sid=(select sid from v$mystat where rownum=1));
    update t set unindexed=lower(unindexed) ;
    update t set indexed=lower(indexed);
    2、ORA-01555:snapshot too old 错误
    错误原因:undo段太小,不足以在系统上执行工作;你的程序跨commit获取;块清除。
    解决方案:适当地设置参数undo_retention(要大于执行查询嘴上的事务所需的时间),可以用v$undostat来确定长时间运行的查询的持续时间,另外,要确保磁盘上已经预留了足够的空间,使undo段能根据所请求的undo_retention增大。
    使用手动的undo管理时加大或者增加更多的回滚段。这样在长时间运行的查询执行期间,覆盖undo数据的可能性降低。
    减少查询的运行时间(调优)。
    收集相关对象的停机信息,这个有助避免块清除导致的错误。
    3、undo段大小确定
    undo段管理方法:
    自动undo管理:通过undo_retention参数告诉oracle要把undo段保留多少时间。oralce根据并发工作负载来确定要创建多少个undo段,以及每个undo段应该多大,这个undo管理的推荐方法。
    手动undo管理:dba根据估计和观察到工作负载,确定手动的创建多少个undo段,dba根据事务量和长时间运行查询的长度来确定这些undo段应该多大。(问题:控制的参数有多少?)
    在手动undo管理中,undo段不会因为查询而扩大,只有insert、update和delete才会让undo段增长。所以dba需要定时调整undo段的大小。
    在手动undo管理中,回收机制是首先回收最小的undo段,如果所有的undo段的大小相同,会回收最老的undo段。因此遇到ora-01555错误可能是系统中最小的回滚段指示的,就算你增加一个大的undo段也不能解决此问题,故建议设置一致的undo段大小。
    4、延迟块清除
    在块清除过程中,如果一个块已经修改,下一个会话访问这个块时,可能必须查看最后一个修改这个块的事务是否还是活动。一旦确定该事务不再活动,就会完成块清除,这样另外一个会话访问这个块时就不必再经历同样的过程。要完成块清除,oracle会从块首部确定前一个事务所用的undo段,然后确定从undo首部能不能看出这个事务很久以前就已经提交,它在undo段事务表中的事务槽以及被覆盖,另一种情况是commit scn孩子undo段的事务表中,这说明该事务只是刚刚提交。

  • 相关阅读:
    TabControl添加关闭按钮
    C# 遍历窗体上控件方法
    个人JS脚本验证大全[转]
    c# 窗体位置任意调
    Sql存储过程解密算法 破解微软的加密算法
    网页居中
    兼容IE和Firefox的设为首页和收藏的Javascript代码
    定义类成员
    HikariCP
    post请求重定向到get请求问题
  • 原文地址:https://www.cnblogs.com/luoyx/p/2298669.html
Copyright © 2020-2023  润新知