本人小菜鸟一枚,最近在学习MySQL(边学MySQL边对比Oracle)时遇到一个问题
MySQL通过double write避免了partial page write.这个partial page write感觉就相当于Oracle的split block.那么Oracle如何保证写脏块时不会产生split block呢?我知道rman可以避免split block是因为它以oracle block size作为最小IO单位,如果发现checksum不一致,就会重读,通过反复读避免split block. 当执行手工begin backup命令时,each time a block is changed the datbase writes the before-image of the entire block to the redo stream before modifying the block. Then, the database also records the changes to the block in the redo log,通过将oracle block的前镜像写入redo,使得在恢复是能够获取oracle block的整个before-image,以此为基础,在通过redo中的记录进行恢复.所以如果想要恢复split block,是要有该split block的整个前镜像的吧.但是在正常的dbwr写脏块时,是不会记录befor-image到redo的吧.那么Oracle怎么解决这个问题啊

解决方案 »

  1.   

    恢复.所以如果想要恢复split block,是要有该split block的整个前镜像的吧.不懂 MySQL的原理,你说的这个,应该是 Oracle 的 UNDO ,你先百度了解一下;
      

  2.   

    split block是指:一个 Oracle block 由多个 OS block 组成,写入必定有先后。那么外部工具备份是以 OS block 为单位备份,就可能发生一个 Oracle block 下的多个 OS block 版本不一致的情况。
    而rman是把这一组 OS block 作为一个整体单位来处理的,全部读进来,如果版本一致可以写入备份,如果不一致全部重读。
    所以读脏块没关系,只要有办法检测出不一致,直接把不一致的数据丢弃重读就行。
      

  3.   

    跟undo没关系吧引用一段<<MySQL技术内幕:InnoDB存储引擎>>书中对double write的描述内容:
    如果说Insert Buffer带给InnoDB存储引擎的是性能上的提升,那么doublewrite(两次写)带给InnoDB存储引擎的是数据页的可靠性。当发生数据库宕机时,可能InnoDB存储引擎正在写入某个页到表中,而这个页只写了一部分,比如16KB的页,只写了前4KB,之后就发生了宕机,这种情况被称为部分写失效(partial page write)。在InnoDB存储引擎未使用doublewrite技术前,曾经出现过因为部分写失效而导致数据丢失的情况。有经验的DBA也许会想,如果发生写失效,可以通过重做日志进行恢复。这是一个办法。但是必须清楚地认识到,重做日志中记录的是对页的物理操作,如偏移量800,写'aaaa'记录。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。这就是说,在应用(apply)重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是doublewrite。
      

  4.   


    令我产生疑问的不是脏读,是Oracle block和OS block大小不一样.Oracle写一个oracle block到磁盘,加设8K,而一个OS block可能是4K,那么有可能产生这两个4K的块不一致,oracle如何保证不会产生这种不一致?
      

  5.   

    跟undo没关系吧引用一段<<MySQL技术内幕:InnoDB存储引擎>>书中对double write的描述内容:
    如果说Insert Buffer带给InnoDB存储引擎的是性能上的提升,那么doublewrite(两次写)带给InnoDB存储引擎的是数据页的可靠性。当发生数据库宕机时,可能InnoDB存储引擎正在写入某个页到表中,而这个页只写了一部分,比如16KB的页,只写了前4KB,之后就发生了宕机,这种情况被称为部分写失效(partial page write)。在InnoDB存储引擎未使用doublewrite技术前,曾经出现过因为部分写失效而导致数据丢失的情况。有经验的DBA也许会想,如果发生写失效,可以通过重做日志进行恢复。这是一个办法。但是必须清楚地认识到,重做日志中记录的是对页的物理操作,如偏移量800,写'aaaa'记录。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。这就是说,在应用(apply)重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是doublewrite。
    嗯。 
      

  6.   

    您说的对,我也感觉需要split block的前镜像,但是正常dbwr写脏块到磁盘时.
    加上oracle block 大小为8K, OS block大小为4K,那么此时一个oracle blokc= 2* OS block
    加入dbwr在写脏块,写了前4K,此时发生crash,比如电源挂了,那么这个oracle block的前4k和后4k就不一致了,对于这种不一致的oracle block,通过redo没法恢复吧. 那么oracle如果保证不会产生我假设的这种情况呢?MySQL通过double write避免这种问题
    在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,将更改真正的写入目标对应得数据文件中在数据写失败时会有一下2种情况。
    -如果是写doublewrite buffer本身失败,那么这些数据不会被写到磁盘,也就是真正的page没有损坏,innodb此时会从磁盘载入原始的数据,然后通过innodb的事务日志来计算出正确的数据,重新 写入到doublewrite buffer-如果 doublewrite buffer写成功的话,但是写磁盘失败(通过对比checksum判断),innodb就不用通过事务日志来计算了,而是直接用double write buffer的数据再写一遍.
      

  7.   

    这2个4k本身就在Oracle的缓存中,要取数据直接从缓存中取,总是一致的。
    只有Oracle之外的程序才从硬盘读,从而发生读到4k旧、4k新数据的可能。
      

  8.   

    这2个4k本身就在Oracle的缓存中,要取数据直接从缓存中取,总是一致的。
    只有Oracle之外的程序才从硬盘读,从而发生读到4k旧、4k新数据的可能。这两个4K的os block对应一个Oracle block,写入过程中写了第一个4K,然后服务器断电了.现在就很有可能前4K和后4K checksum不一致. 和在缓存中有啥关系?服务器都挂了,硬盘中的oracle block已经被修改了一部分了,后面那4K没改成功
      

  9.   

    中间断电,日志中该操作没完成,重启后会回滚(恢复上个版本数据)。
    总之数据库是以8k作为一个原子来操作的,对数据库而言,并不存在(需要)4k成功4k不成功的这样的状态,只有(只需要)8k不成功状态就行。
      

  10.   

    中间断电,日志中该操作没完成,重启后会回滚(恢复上个版本数据)。
    总之数据库是以8k作为一个原子来操作的,对数据库而言,并不存在(需要)4k成功4k不成功的这样的状态,只有(只需要)8k不成功状态就行。
    redo肯定是在dbwr写脏块前就把日志写入磁盘了,而dbwr写脏块是在之后发生,如果出现写数据块不一致,redo中也不会记录该操作是否完成吧
    第二句还靠谱,我再ITPUB上也看有人这么说,你们的意思就是Oracle写脏块时以Oracle block为最小IO单位吗?oracle直接去写数据文件,不经过操作系统?如果Oracle可以控制以自身Oracle block为原子进行写数据,那么到时可以避免partial write.但是我又产生了疑问,如果oracle可以做到为什么mysql不这么做呢,有没有能证实您说法的文档?
      

  11.   

    中间断电,日志中该操作没完成,重启后会回滚(恢复上个版本数据)。
    总之数据库是以8k作为一个原子来操作的,对数据库而言,并不存在(需要)4k成功4k不成功的这样的状态,只有(只需要)8k不成功状态就行。您说的"数据库是以8k作为一个原子来操作的"有没有官方文档,或者其他文献资料可以证实?或者您通过实验证实?我觉得MySQL通过double write也只是避免了自身crash导致的数据损坏,没法保证操作系统再写page的过程中断电是否会造成os block损坏,至于OS有什么机制避免,我还不清楚
    但是假设oracle以oracle block为最小IO单位写数据,它怎么保证自己再写了8K中的一部分时,数据库崩溃不会造成partial write,除非他先写到一个临时文件,写成功了在去写真正的数据块"中间断电,日志中该操作没完成,重启后会回滚(恢复上个版本数据)。" 您的意思是说,dbwr写脏块的过程还要记录在redo中?,写完了在redo中标记写成功?恐怕不是这样吧
      

  12.   

    [http://blog.163.com/bihonggang_anshan/blog/static/13171564320118143472780/]oracle 写入数据的过程[/url]
    Oracle中SGA与PGA的异同点是什么
    对于任何一个完善的数据库,这是封装好的底层基本功能,属于无需关心的部分。
    想了解自己找文档看,远比你想象的/平时简要描述的要复杂的多。
      

  13.   

    我在这里要讨论的就是你说的底层,我发文也是翻过oracle官方文档,MOS,ITPUB得不到答案才来提问的.从你一开始说什么"在Oracle的缓存中","中间断电,日志中该操作没完成,重启后会回滚".这都不是我要讨论的问题.
    不管什么数据库,对操作系统来说都是是一个软件,是软件就要协同操作系统完成任务.MySQL知道以自己的page进行写,要调用系统方法实现,而系统块大小与MySQL page不符,所以才有了double write.而Oracle如果解决官方文档中并没有体现.
    我要再次引用<<MySQL技术内幕:InnoDB存储引擎>>中的描述
    当发生数据库宕机时,可能InnoDB存储引擎正在写入某个页到表中,而这个页只写了一部分,比如16KB的页,只写了前4KB,之后就发生了宕机,这种情况被称为部分写失效(partial page write)。在InnoDB存储引擎未使用doublewrite技术前,曾经出现过因为部分写失效而导致数据丢失的情况。有经验的DBA也许会想,如果发生写失效,可以通过重做日志进行恢复。这是一个办法。但是必须清楚地认识到,重做日志中记录的是对页的物理操作,如偏移量800,写'aaaa'记录。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。这就是说,在应用(apply)重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是doublewrite。实例恢复是以健康的数据块为基础,应用日志,前滚回滚,完成实例恢复,构造buffer中的数据块.而如果块本身已经corrupt,是不能以此作为基础再通过日志进行恢复的,至少MySQL不能,所以有了double write.而我在这里问的就是Oracle如何解决,这是对比学习的方法恕我直言,没有文档,文献,实验支持的结论都是耍流氓.不能说"任何一个完善的数据库,这是封装好的底层基本功能,属于无需关心的部分"就相当然的认为别人是这样的做的,这不是做技术的学习方法.网上涉及的文章,都没有详细说明.
    http://www.vmcd.org/2014/09/1748/comment-page-1/#comment-343836
    https://community.oracle.com/thread/1087650?start=0&tstart=0
    http://www.ixora.com.au/tips/use_raw_log_files.htm
      

  14.   

    你问: Oracle 避免 split block 的方式。
    其实一句话就可以回答:把属于同一个 oracle block 的 OS block 作为一个原子进行控制就行。
    其余的就是你在不停地追加细节问题了。如果仅仅是学会使用数据库,你把它看成一个黑箱功能,反正数据库保证做到,能用就行。
    如果你想学着编写一个数据库系统,先从大概原理来,可以看看我的回复。
    如果你就追究Oracle是怎么做的,请忽略我的回复,去看文档。