
当某个事务开始的时候,会在回滚段的段头 TRN TBL 中分配一个事务表记录,同时分
配第一个 UNDO 记录,记下事务的一些信息。当事务修改某个数据的时候,在该数据的 DATA
BLOCK 的 ITL 表中分配一个 ITL 记录,并锁定这个 ITL 记录,然后将数据行头中的 kdrhlock
指向这个 ITL 槽,然后再对数据进行修改。并把修改前的数据存储在回滚段的 UNDO
RECORD 中。
如果有事务要读取相关的数据,首先对数据库的 DB CACHE 缓冲区进行搜索。在 Oracle
的 DB CACHE 中,同一个数据块可能存在多个版本,这些版本被称为 CR BLOCKS。如果
在 DB CACHE 中已经找到了符合条件的 CR BLOCK(根据 SCN 来判断 CR BLOCK 是否
符合查询条件),就可以直接使用,如果没有找到可用的 CR BLOCK,那么就需要通过该
数据块的当前版本(CURRENTBLOCK)来生成所需要的 CR BLOCK。
在生成 CR BLOCK 的时候,可以根据该行数据的 kdrhlock 找到相关的 ITL 槽,通过比
对 SCN 来判断要读取的数据是数据块中的数据还是修改前的数据。如果发现当前 ITL 槽中
的 SCN 高于本事务所需要读取的 SCN,那么就会通过 ITL 槽找到该数据在 UNDO 中的前
映像数据(PRE-IMAGE),通过前映像数据和当前数据生成一个一致性读块(CR BLOCK),
然后通过访问这个 CR BLOCK 来找到所需要读的数据。实际环境中可能更为复杂,因为 ITL
槽可能会被覆盖,在这种情况下,Oracle 会把 ITL 信息写入 UNDO RECORD 中,形成一
个链状结构,可以一层层的找到所需要的 UNDO RECORD,从而完成这种操作。
Oracle 的多版本并发控制机制使用了一个独立的 UNDO 表空间来存储 UNDO 数据,
数据的前映像通过在 DB BUFFER 中的 CR BLOCK 来实现,因此数据无论修改多少次,都
不会对存储数据的数据段产生负面的影响。而且一个 CR BLOCK 生成后,可以在缓冲区中
较长时间内存在,供相关的事务使用。这个功能对于大并发的读操作来说,是十分有用的,
可以大大提高相关操作的性能。
由于 Oracle UNDO 的空间容量有限,因此不可能永久保存回滚段的数据,Oracle 采用
了 UNDO RETENTION 的机制来保护 UNDO 数据,可以设定一定的 UNDO 数据保存周期,
当 UNDO 数据在保护期内,可以保证 UNDO 记录不被覆盖。这种机制很好的解决了 UNDO
数据生命周期管理的问题,同时确保了在一个大型查询中确保所需的 PRE-IMAGE 不会被
覆盖失效。
PostgreSQL 早期的版本中是不支持多版本并发控制的,因此 PostgreSQL 的多版本并
发控制不是通过类似 Oracle 的回滚段方式实现的,其实现手段是在数据表中保存某条数据
的多个版本。比如说要对某条记录进行修改,并不是直接修改该数据,而是通过插入一条全
新的数据,同时对老数据加以标识。而删除数据也不是直接删除该数据,而是在相应的数据
相关文档
评论