oracle online系列(二):online indexbuild

online indexbuild (online create或者rebuild index)是oracle的一个非常常用的online操作,我们知道当创建索引或者重建索引没有加online关键字的话,会请求表对象上的4号TM锁,而DML请求的是3号TM锁,3和4的TM锁并不兼容,所以在索引创建或者重建期间是无法进行DML操作的,等待事件为enq: TM – contention。为了改进这一缺陷,在oracle 8i推出了online indexbuild功能,并且在11.1该功能得到了进一步增强。online indexbuild就不会影响其他DML操作的正常运行。本文将深入解析 online indexbuild的工作原理。

在分析online indexbuild实现原理之前,先介绍一下 indexbuild online与非online除了对表持有的TM锁级别不同之外的第二个比较大的区别,就是 indexbuild的执行计划不同。

  • indexbuild online只能使用全表扫描的方式
  • indexbuild非online,遵循CBO最小cost原则去选择执行计划,索引快速全扫描或者全表扫描

这应该是indexbuild的代码kdic.c中限定的,online indexbuild就只能全表扫描,有这样一段话描述了在设计online indexbuild功能时,索引快速全扫描比全表扫描要难实现很多。

Restartable online indexbuild, means that online build can proceed after the databaserestarts. It is hard to implement because current Oracle implementation does not supportrestartable sort.(it is a future ehancement)• Build the new indexby scanning fromthe old indexsegment. Because the indexrowsmove fromone block to another block in the indexblock split, reading from indexisdifficult to implement than reading from table

那么online indexbuild,是如何不影响dml操作的情况下完成索引创建的呢?我们通过测试来验证,由于online create index和online rebuild index在实现原理上基本一致,所以此次测试online rebuild index即可,测试环境选择的11.2.0.4,通过gdb在kdic.c的重要函数kdicdrv、kdic_create_journal_table、kdic_indrebuild_set_oldidx_fields、kdic_indrebuild_update、kdic_indrebuild_delete上打断点,结合event 10046、event 10704进行深入分析。

测试使用的是TEST.T1表上的索引TEST.I1

第一步:发起online rebuild index,调用kdicdrv接口进行索引重建,该步骤就会对表持有2号的TM锁

第二步:调用kdic_create_journal_table,创建一个命名为 sys_journal _indobject#表的索引组织表,并持有该表的4号TM锁,该表对于online indexbuild非常重要,其设计目的是为了记录索引的变更。

第三步:正式开始进行索引重建,该过程会对ind$、ind_online$做一些变更说明该索引处于online rebuild状态,修改flags为0xa02,并且在索引未创建完成期间新的索引会以临时段存在

在此过程中的DML操作如果涉及对该索引的变更都会记录在journal表中,update会以INSERT+DELETE形式记录

第四步:索引初步重建完成之后,会调用kdic_indrebuild_update函数对ind$和ind_online$的flags进行修改,表示索引初步已创建完成。并且临时段”转正”了。但是在重建期间的dml涉及该索引的变更还没有作用在新索引上。

第五步:调用kdic_do_merge函数将 journal表记录的变更合并到新索引上。该阶段在merge过程中接受的dml操作会不断的merge,直至final merge,如果事务未提交,merge请求的4号锁将被TX 6号锁阻塞。

During the merge process, Oracle will read the journal table (IOT) leaf blocks from left to right to merge those changes with the index being built. As the journal table leaf block changes are applied, once a leaf block is fully consumed, it’s reference will be deleted from the branch block.

This process will continue until all leaf blocks are consumed and when it comes to the last leaf block, Oracle would stop all the DML’s again to do the final merge and drop the journal table before releasing the mode 6 exclsuive table lock.

但是通过event 10704并未看到进程请求过6号TM锁,如果在线重建索引merge期间,有大量的DML操作,那么merge操作将可能会被阻塞。

第六步:再次调用kdic_indrebuild_update 对ind$和ind_online$的flags进行修改,并且进行索引切换。切换完成之前,dml操作会被阻塞,原因是在此阶段会在表和索引的library cache handle上加持有X模式的lock,而dml操作会以S模式请求表的library cache handle的lock,会被X模式阻塞。这样做的目的是为了保证在切换过程中,不再接收新的变更,保证在后续新老索引切换时保证一致性。切换完成之后释放表和索引的library cache handle的X模式lock,此时就不会阻塞DML操作了。

第七步:调用kdic_indrebuild_delete函数,并且做online indexbuild的收尾工作,删除 journal、修改索引flags、释放表上的2号TM锁等等

至此online indexbuild流程完毕。

此条目发表在Oracle分类目录,贴了, , 标签。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注