事物深度解析

事物深度解析

一、部分概念及理论

1、快速提交

Oracle数据库事物信息会分布在:

(1)undo段头块事务表。

(2)数据块事物槽。

(3)数据块中的数据行。每更新修改一条数据,都会在行头部写入事物信息。

如果数据库事物提交,则需要更新各个角落的事物信息,造成提交缓慢。目前,oracle采用快速提交。

   当一个事务涉及到要修改很多个数据块时,为了避免要在每个数据块头部都进行修改,而仅仅只修改undo段的事务表的提交标识。所以只有undo段的事务表中的提交信息才是最准确的。

   当一个事物更新一个数据块的数据行时,如果发现,这个数据行的头部存在事物,则找到该数据行所在的数据块的块头,看对应的事物是否已经提交,如果已经提交,就可以修改相应的数据行。如果未提交,因为数据块的事物槽中的事物是否提交标识不一定准确,所以,需要根据xid找到undo的段头块中的事物信息,看是否已经提交,如果已经提交,则可以更新数据块,并且,更新数据块中上一个事物槽中记录的错误信息。如果没有提交,则需要等待。

2、查询产生REDO的原理

   当select语句扫描到一行,发现行头部有锁标识,然后找到该行对应的事务槽中的事务信息,如果提交标识没有显示提交,然后再根据xid找到事务表,如果其中的事务信息,显示该事务已经提交,则select语句会将事务槽中的提交标识和数据行头部的锁标识分别设置为提交和null。所以就产生了redo log信息。

如果事物表中的事物信息为未提交,则需要根据UBA找到undo信息,构造CR块访问,从而保证了数据库的读写一致性。

3、行级锁

   数据块中的每一行数据的头部有一个事务槽编号的字段,当该行被一个事务修改时,则在该字段填上该事务对应的在事务槽中的ITL编号,来表示该行被锁定了。如果该字段为null则该行没有被锁定。当然,如果该字段不为null时,也不能肯定该行被锁定了,还要看事务槽中的提交标记,甚至还要看事务表中的提交标识。因为快速提交时,有可能只修改事务表中的提交标识。

二、事物流程深度解析


    事务开始,必须首先在data block中分配ITL,ITL中记录了事务ID(XID),XID由三部分内容组成:XIDUSN(回滚段号),XIDSLOT(回滚段槽号),XIDSQN(序列号),在Undo segment header(段头块)中有一个事务表,记录该回滚段上的事务信息,每个事务都会占据了一个回滚槽,XID对应一个UBA(undo block address),表示该事务回滚信息的开始位置。 在上面的例子中,事务分别在T1,T2,T3时间执行了三个操作,更新了三个block中的数据,在每个data block中都存在一个ITL,指向段头块中的事务表。undo信息分别存放在三个undo block中,undo信息是一个链表结构,而undo segment header中的uba则指向了最后一个undo block,这也是回滚的起始位置。如果事务需要回滚,只需要在undo segment header中的事务表中找到事务回滚的起始位置,然后通过undo链表,就可以依次回滚整个事务。

     在每个data block的ITL中也有一个UBA,实际上这个UBA是指向了该block对应的undo信息的起始位置,这个UBA主要的作用是提供一致性读,因为一 致性读需要通过undo信息来构造一个CR block,通过这个UBA就可以直接定位到block的回滚信息的起始位置,而不再需要通过undo segment header中的事务表。

   在传统的undo管理模式中,Oracle对于undo和data block是一视同仁的,他们都需要首先读入到data buffer中进行修改,并都会产生redo信息,修改的过程大致是:产生undo的redo,更改undo block,产生data的redo,修改data block。总之redo必须要先于数据被记录下来。当数据库发生crash,可以通过redo日志,恢复data和undo block,然后再通过undo信息去回滚未提交的事务,保证数据的一致性,所以说instance recovery的过程是先前滚,再回滚的过程。

   传统的undo管理有弊端,第一是undo信息如果不在data buffer中,必须首先从外部文件中读入;第二是undo的所有变化也必须同时记录redo,在事务提交时被写入到redo log中。Oracle提出了In-Memory UNDO的新特性,将undo信息都存放在内存结构中,缓解传统undo管理中带来的开销。

三、IMU机制

IMU机制用来解决上面描述的传统UNDO管理的弊端。ORACLE构造CR块的速度大幅提升。

 

    IMU在shared pool中分配一片内存空间(IMU pool),每个新的事务都会分配一个IMU buffer,它相当于一片事物私有的undo buffer,用来记录undo的信息。Data block中记录了IMU node的起始位置,通过IMU buffer中的信息就可以完成一致读,从而大大提升了效率。

  在IMU模式下,undo信息依然会被写入到redo中,理解这点很重要!因为Instance recovery需要undo的信息去回滚未提交的事物,使数据库处于一致状态,如果redo中没有undo变化的信息,那么一旦发生Instance crash,数据库将有可能处于一个不一致的状态。

  事务开始依旧会在data block中的分配ITL,并且它依然会指向undo segment header的事物表,但是undo block中的信息并不需要马上写入,这时undo信息是记录在IMU Buffer中的,这时也不会产生undo block的redo信息。在以下两种情况时,undo buffer中的信息会被写入到undo block中:1.IMU buffer空间不足;2.LGWR将redo信息被写入到redo log中时(比如commit),在v$sysstat中可以看到IMU flush和IMU commit,分别表示以上两种情况,如果你发现这两个值不断增加,代表系统开启了IMU特性。

  现在我们已经了解到,IMU中的undo信息依旧会被写入到redo log中,只不过在shared pool中分配了一个private undo buffer,一方面可以在内存中完成一致读的操作,另一方面,undo信息只在必要情况下批量写入到redo log中,保证数据库crash后可以恢复到一致状态。另外,Oracle总是会尽可能的保留undo buffer中的信息,以便可以在内存中完成一致读的操作,而且undo信息在写入undo block时,Oracle进行了合并处理,减少了undo block的消耗量和对应的redo产生量。

  从Oracle 10g开始,引入了private redo strands的概念,在shared pool中分配了一个private redo buffer的空间,每个事务产生的redo都放在这里(9i是放在PGA里面),每个buffer分配一个redo allocation latch,用来解决9i中redo allocation latch的争用问题。其实IMU和private redo strands这个特性是相关的,IMU相当于private undo buffer,当redo strand或者undo buffer空间不足时,会发生IMU flash事件,将redo信息(包括undo)写入到redo log中。

   IMU实现复杂,在很多情况下Oracle会自动禁用IMU特性,比如RAC和Stream环境。

原文地址:https://www.cnblogs.com/ironyoda/p/6065611.html