ORACLE的工作机制-2


生成代码之后,接着下一步进程要准备开始更新数据,进程将到DB BUFFER中查找是否有相关对象的缓存数据,下面分两个可能进行解释:
如果没有,进程将在表头部请求一些行锁,如果成功加锁,进程将从数据文件中读入这些行所在的第一个数据块(db block)(DB BLOCK是ORACLE的最小操作单元,即使你想要的数据只是DB BLOCK中很多行中的一行或几行,ORACLE也会把这个DB BLOCK中的所有行都读入DB BUFFER中)放入DB BUFFER中空闲的区域或者覆盖已被挤出LRU列表的非脏数据块缓冲区,并且排列在LRU列表的头部,如果这些非脏数据缓冲区写完也不能满足新数据的请求时,会立即触发DBWN进程将脏数据列表中指向的缓冲块写入数据文件,并且清洗掉这些缓冲区,来腾出空间缓冲新读入的数据,也就是在放入DB BUFFER之前也是要先申请DB BUFFER中的锁存器,成功锁定后,再写入DB BUFFER,然后把这个块的头部事务列表及SCN信息及被影响的行数据原值写入回滚段中,以便ORACLE在ROLLBACK时可以利用当前数据块和回滚段重构数据块的”前映像”或递归重构出”前…前映像”来实现读一致性。(回滚段可以存储在专门的回滚表空间中,这个表空间由一个或多个物理文件组成,并专用于回滚表空间,回滚段也可在其它表空间中的数据文件中开辟。)然后在LOG BUFFER中生成日志,程将该语句影响的被读入DB BUFFER块中的这些行的ROWID及将要更新的原值和新值及SCN等信息,以及回滚段的修改信息(即对某某回滚段地址进行了什么修改)逐条的写入REDO LOG BUFFER,在写入REDO LOG BUFFER之前也是先请求REDO LOG BUFFER块的锁存器,成功锁定之后才开始把REDOLOG写入REDOLOG BUFFER。当写入达到REDO LOG BUFFER大小的三分之一或写入量达到1M或超过三秒后或发生检查点时或者COMMIT时或者DBWN之前触发LGWR进程,LGWR将把REDO LOG BUFFER中的数据写入磁盘上的重做日志文件,已被写入重做日志文件的REDO LOG BUFFER中的块上的锁存器被释放,并可被后来写入的信息所覆盖。回滚段其实也有BUFFER(在DB BUFFER中开辟),回滚段BUFFER中的内容是最早向磁盘上回滚段中写的,写完这些才会生成日志BUFFER中的内容,原因是日志中必须要记录回滚段的新旧变化以便在恢复时从日志中的记录的回滚段新旧变化对回滚段再次重写,记住,REDO不光是对数据文件依据日志文件重写,也要依据日志文件对回滚段重写,而且重写回滚段要先于重写数据文件,要理解REDO就是重来一遍,所谓重来一遍就要跟正常的的先后顺利一样重做一遍(正常的操作中的顺序就是先读入DB BUFFER,写回滚段buffer,后写回滚段,后写日志BUFFER,后改写DB BUFFER,后写日志最后写数据文件)区别是REDO时不用再记日志了,这样解释后相信大家应该理解为什么日志中也必须要记录回滚段的信息了,只有这样才可以对正常操作中的一个ROLLBACK动作进行恢复,即在REDO过程中利用即时重写的数据块和回滚段重构出一个当时适用的前镜像来rollback。当一个重做日志文件写满后,LGWR将切换到下一个重做日志文件,重做日志文件也是循环工作方式。如果是归档模式,归档进程还将前一个写满的重做日志进程写入归档日志文件。当DB BUFFER改写之后,服务器进程在脏数据列表中建立一条指向此DB BUFFER缓冲块的指针。接着服务器进程会从数据文件读入第二个数据块(db block)重复以上读入,建立回滚段,写LOG BUFFER,改写DB BUFFER,放入脏列表的动作,当脏数据列表达到一定长度时,DBWN进程将脏数据列表中指向的缓冲块全部写入数据文件,也就是释放加在这些DB BUFER块上的锁存器,并在修改相应块的头部的SCN号(一次UPDATE操作只对应一个SCN)。前面说过DBWN动作之前会先触发LGWR,这用以确保写入数据文件的改变首先会被记录在日志文件中。实际上ORACLE可以从数据文件中一次读入多个块放入DB BUFFER,然后再对这些块建回滚段、再记日志等等,也就是每次操作的对象是DB BLOCK的复数,而不仅限于一次操作一个DB BLOCK,可以通过参数DB_FILE_MULTIBLOCK_READ_COUNT来设置一次读入的块的个数。注意,不管是否提交,用户的所有更改都会被记录在日志文件中,用户级回滚的动作(rollback)没有对应的COMMIT SCN。在密集事务的情况下,LGWR可以把多个COMMIT产生的REDO条目批量写入REDO LOG FILE,但每个COMMIT之间有十分之一秒的间隔,且会产生不同的COMMIT SCN。LGWR正常情况下是一个休眠进程,会被一定的条件触发,唤醒,比如COMMIT就是一个唤醒条件,一旦LGWR被唤醒,LGWR将把唤醒时间点之前LOG BUFFER中产生的所有内容(从上次LGWR唤醒后到本次唤醒前之间写入LOG BUFFER的内容)写入LOG FILE,直到LGWR完成后,LGWR才可以被再次触发,在LGWR触发到完成期间所有对的操作仍然可以不间断的加入LOG BUFFER。在这段时间内,LGWR不再接收其它条件的触发,比如紧跟前一个COMMIT之后的其它COMMIT(复数)都要等待LGWR完成后才可以再次触发LGWR,并在LGWR下次被触发时,将积累的REDO BUFFER条目一次性写入REDO LOG,后继的COMMIT不会单个单个的触发LGWR。
如果要查找的数据已缓存,则根据用户的SQL操作类型决定如何操作,如果是SELECT则查看DB BUFFER块的头部是否有事务,如果有,将利用回滚段进行重构出一致性块再读取,如果没有则比较SELECT的SCN与DB BUFFER块头部的SCN如果比自己大,仍然同上,如果比自己小则认这是一个非脏缓存,可以直接从这个DB BUFFER块中读取。如果是UPDATE则即使在DB BUFFER中找到一个没有事务,而且SCN比自己小的非脏缓存数据块,服务器进程仍然要到表的头部对这条记录申请加锁,加锁成功则进行后续动作,如果不成功,则要等待前面的进程解锁后才能进行动作。

声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 智乐兔
转载请注明:转自《ORACLE的工作机制-2
本文地址:https://www.zhiletu.com/archives-257.html
关注公众号:智乐兔

赞赏

wechat pay微信赞赏alipay pay支付宝赞赏

上一篇
下一篇

相关文章

在线留言

你必须 登录后 才能留言!

在线客服
在线客服 X

售前: 点击这里给我发消息
售后: 点击这里给我发消息

智乐兔官微