ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 9I/10G 11G online index的实现过程分析

9I/10G 11G online index的实现过程分析

原创 Linux操作系统 作者:wei-xh 时间:2012-05-09 15:45:27 0 删除 编辑
[i=s] 本帖最后由 wei-xh 于 2012-5-9 15:42 编辑

ORACLE 的ONLINE 创建索引在很多手册上被描述为:不阻塞写的安全操作。但是11G前,ORACLE一直没能真正做到这一点。
MYSQL ,POSTGRES里好像也一直没能实现ORACLE ONLINE的功能,他们的创建都会阻塞写操作。我们这里分析下ORACLE ONLINE创建索引的步骤。

9I、10G版本下ONLINE REBUILD创建索引的过程。
创建索引前,开启如下跟踪事件,第一个等待事件,可以观察到锁的申请情况。第二个等待事件可以观察到递归执行的SQL。

alter session set events '10704 trace name context forever,level 10';
alter session set events '10046 trace name context forever,level 12';

ORACLE ONLINE REBUILD索引的思路就是通过:
索引创建开始时候的数据+MRGEE索引创建过程中的增量来完成整个创建。

索引创建开始时候的数据:通过一致性读来实现
索引创建过程中的增量:  通过IOT表记录的变化日志来实现。

整个过程分为如下几个步骤:

1.申请表上类型为2的TM锁。创建IOT表,用来捕获增量。

CODE:

跟踪文件摘要:
*** 2010-07-27 23:07:16.000
ksqcmi: TM,18fe,0 mode=2 timeout=21474836
ksqcmi: returns 0
create table "SYS_JOURNAL_6399" (C0 NUMBER, opcode char(1), partno number, rid rowid, primary key( C0 , rid ))
organization index TABLESPACE "USERS"
CREATE UNIQUE INDEX "SYS_IOT_TOP_6406" on "SYS_JOURNAL_6399"("C0","RID") INDEX ONLY TOPLEVEL TABLESPACE "USERS" NOPARALLEL
创建IOT表的时候,持有的是原表上2的TM锁。这是个非常低级别的锁。即使此时,表上有未提交事务,也不会阻塞这个操作,因为DML操作获得的3类型的TM锁与2类型的TM锁具有兼容性。

2.将类型为2的锁转化为类型为4的TM锁。为了阻塞后续的DML操作。
ORACLE在ONLIEN创建索引过程中,通过一致性读取表段+IOT表增量 来完成整个创建。IOT表记录了,一致性读取表数据后的发生的所有数据变化。
因此在真正开始一致性拷贝旧数据之前,需要确保表上没有事务。
可以设想一下,如果ORACLE不保证表上所有的事务已结束就开始一致性读取,那么一致性读取表数据建立的索引段+IOT表MERGE完成后,就会丢失数据。IOT表只记录了一致性读取表数据后的所有数据变化。对于之前的变更不做记录。

举个例子:数据块1的一条记录做了修改,把A值变为了B值,但是这个事务没提交,如果ORACLE不等待这个事务结束就开始创建索引,那么一致性读取数据块的内容,读取到的将是内容A。在创建索引过程中,这个事务提交了,但是这个B并不会进入到IOT表里,因为这个事务是索引创建开始前开始的,IOT表不记录。最终索引创建完成后,这个B会丢失。

因此ORACLE在这个步骤里申请了一个等级稍微高点的TM 4锁,假如表上存在事务,那么这个4的TM锁将不能获得,因为它与事务的TM 3锁冲突。持有这个TM 4锁,还为了阻塞后面的DML操作,为了让索引重建尽快可以开始。而这个持有的TM 4锁,经常是我们在ONLINE 创建索引过程中,风险最大的地方。因为这个4锁一旦获得不了,它将会阻塞后续的所有的DML操作。

CODE:

跟踪文件摘要:
*** 2010-07-27 23:07:16.000
ksqcmi: TM,18fe,0 mode=4 timeout=21474836
WAIT #1: nam='enqueue' ela= 3072242 p1=1414332420 p2=6398 p3=0

3.因为DML操作都获得的是TM为3的锁,它跟4 TM锁不兼容,因此一旦可以获取到类型为4的TM锁,代表表上事务都已经结束,这个时候,就可以释放这个TM 4锁,将锁降级为类型为2的TM锁。至此,开始读取表数据建立索引。需要注意的是,这里的读取表数据,是一致性读取。
建立新索引的时间要依据表的大小。整个过程要做的事情就是一致性读取表数据+排序

CODE:

跟踪文件摘要:
*** 2010-07-27 23:07:41.000
ksqcmi: TM,18fe,0 mode=2 timeout=21474836
ksqcmi: returns 0
4.读取IOT表上的变更,在新的索引段上进行MERGE.这个过程中会发现IOT表的记录数逐渐在减少。最终完成时,只剩下未提交事务所修改的记录保留在IOT表里。类似如下的情况。由于这些记录还没提交,ONLIEN进程就只能等待。

CODE:

select * from SYS_JOURNAL_207626;
C0 OP PARTNO RID
---------- -- ---------- ------------------
11 I 0 D/////AAGAAAe4DAAa
11 I 0 D/////AAGAAAe4DAAb
12 D 0 D/////AAGAAAe4DAAa
12 D 0 D/////AAGAAAe4DAAb
12 D 0 D/////AAGAAAe4DAAc
12 D 0 D/////AAGAAAe4DAAd
5.获取表上类型为4的TM锁,等待未提交的事务结束,阻塞后续的事务,以免让索引重建过程“无限期”的等待。这里又是一个风险点,因为申请了一个TM 4锁,会阻塞后面的DML操作。
一旦步骤4里涉及的变更记录都已经提交,那么就会把最终的这批记录MERGE进新索引里。最后删除IOT表。整个过程完毕。

有个疑问,就是在进行MERGE过程中,ORACLE依据什么判断IOT表里那些记录已经提交,那些没提交?IOT表里貌似没这个字段。

看来ORACLE 9I、10G所谓的ONLINE其实并不安全,因为里面有几个地方,会申请一个TM 4的锁,这个锁一旦获取不了,就会导致DML操作的阻塞。

11G后,这个情况完全变了,ORACLE做到了真正的ONLINE.


11G ONLINE REBUILD创建索引的过程。
1.申请表上类型为2的TM锁,创建IOT表。
2.创建完IOT表后,如果表上存在事务,那么会发生等待,不过这个发生的等待是TX事务等待,不是在表上的TM等待了。
3.创建索引进程会被未提交的事务挂起,但是这个时候存在DML操作的话,可以正常进行。但是这些DML操作变更并不会记录进IOT表里。

4.如果表上事务都已经提交,那么进行一致性读取表上的旧数据的过程,然后对数据排序。例如:如果表上存在3个没有提交的事务,那么会先等待事务1,事务1提交后,会等待事务2,事务2提交后,会等待事务3.直到事务3提交,那么才可以进行下一步。这个过程可以通过观察 v$session的P1,P2参数来了解,随着事务的提交,P1,P2的值也会发生变化,P1,P2的值反应了当前等待在哪个事务上。这个过程虽然不会阻塞事务,但是我们不难发现,如果表上事务并发比较大,那么重建索引的进行就会被延期。知道表上的“那一刻”不存在事务。
5.把IOT表里的数据在新索引段上进行MERGE,这个过程中,会发现IOT表的数据逐渐减少。最终只剩下没提交事务的数据。
6.等待IOT表里未提交的事务进行提交,这个时候后台会等待TX事务锁,类型为4.直到所有的事务都已经提交,这个过程才会完成。这个
过程不会阻塞新进的事务,ORACLE会把变更的数据记录进IOT表里(当然要涉及到跟索引字段相关的数据才会被记录进IOT表里)。

11G最大的特点是不需要对TM锁进行锁转化了,11G前由于这种锁转化,可能会阻塞DML操作,可能会引起故障。

但是理论上11G这种做法也会引起问题,因为在第4、6步,在等待事务结束期间,一直有源源不断的事务进来,如果运气差的话,那么你的索引重建时间就会非常长。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22034023/viewspace-723144/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
Oracle ACE组成员,DBGeeK用户组发起人。曾在DTCC、ORACLE技术嘉年华、Gdevops等公开场合做过数据库技术专题分享,2017年应Oracle邀请在世界最大的数据库会议OOW上做技术分享。组织翻译了《拨云见日,解密Oracle ASM内核》一书。

注册时间:2009-07-04

  • 博文量
    422
  • 访问量
    2278832