一般都说,rebuild index online不阻塞DML操作,这是相对于rebuild index来说的,加上了online,只是在rebuild的期间不阻塞DML,但是在开始和结束阶段还是可能阻塞其他进程的DML的,要弄清楚到底是阻塞还是不阻塞,何处阻塞,为什么阻塞,还

是要从锁的角度来分析。本文实验环境为Oracle 10.2.0.1

Oracle中的锁,一共有6两种模式:

0:none
1:null 空
2:Row-S 行共享(RS):共享表锁,sub share
3:Row-X 行独占(RX):用于行的修改,sub exclusive
4:Share 共享锁(S):阻止其他DML操作,share
5:S/Row-X 共享行独占(SRX):阻止其他事务操作,share/sub exclusive
6:exclusive 独占(X):独立访问使用,exclusive

share mode的lock可以被多个session获取,如果多个session 都获取到share lock, 则所有的session都不能对表进行更改操作,只能进行查询
exclusive mode的lock只能被一个session获取,而且其他session也不能对该表加上share 锁来企图阻止获取exclusive 锁的session对表进行更改

DML操作一般要加两个锁,一个是对表加模式为3的TM锁,一个是对数据行的模式为6的TX锁。只要操作的不是同一行数据,是互不阻塞的。但是rebuild index online在开始和结束的时候是需要对表加一个模式为4的TM锁的,这个可以很容易通过实验观察到
实验中的测试表准备:
1)create table t as select * from all_objects;
2)多次执行insert into t select * from t产生较多的数据
3)create index ix_t on t(object_id);

[session 1:]
SQL> delete from t where object_id=25;

32 rows deleted.

SQL> select sid,type,id1,id2,lmode,request from v$lock where type in('DL','TM','TX') order by sid;

       SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
       159 TX     196635        294          6          0
       159 TM      52643          0          3          0

[session 2:]

SQL> alter index ix_t rebuild online;

Session 2被阻塞,会话挂起,这时查询v$lock,可以得到如下结果:

[session 3:]
SQL> select sid,type,id1,id2,lmode,request from v$lock where type in('DL','TM','TX') order by sid;

       SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
       148 TM      52673          0          4          0
       148 DL      52643          0          3          0
       148 DL      52643          0          3          0
       148 TM      52643          0          2          4   --开始时会请求模式为4的TM锁
       159 TX     196635        294          6          0
       159 TM      52643          0          3          0

从上面的结果可以知道,159是session 1,148是session 2,session 2一共出现了4个锁,两个DL锁,一个针对表t的TM锁,一个是online rebuild index时需要的一个中间表的TM锁,中间表用于记录rebuild期间的增量数据,原理类似于物化视图日志,其

object_id为52673,这是一个索引组织表(IOT),从这里我们也可以发现IOT的优点和适合的场合,这张中间表只有插入,不会有删除和修改操作,而且只有主键条件查询,正是IOT最合适的场景:

SQL> select object_id,object_name,object_type from all_objects where object_id in (52673,52643);

 OBJECT_ID OBJECT_NAME                    OBJECT_TYPE
---------- ------------------------------ -------------------
     52643 T                              TABLE
     52673 SYS_JOURNAL_52644              TABLE         ---online rebuild index时需要的一个中间表

SQL> select table_name,iot_type from all_tables where table_name='SYS_JOURNAL_52644';

TABLE_NAME                     IOT_TYPE
------------------------------ ------------
SYS_JOURNAL_52644              IOT

[session 1:] session 执行提交:

SQL> commit;

Commit complete.

[session 3:]

可以看到此时session 2 有5个锁两个DL锁,一个针对表t的TM锁,一个是online rebuild index时需要的一个中间表的TM锁,新增的是对数据行的模式为6的TX锁.(说明重建INDEX是在执行)

SQL> select sid,type,id1,id2,lmode,request from v$lock where type in('DL','TM','TX') order by sid;

       SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
       148 DL      52643          0          3          0
       148 DL      52643          0          3          0
       148 TX     131098        291          6          0
       148 TM      52673          0          4          0
       148 TM      52643          0          2          0

稍等一会就可以看到索引重建完毕:
[session 2:]

SQL> alter index ix_t rebuild online;

Index altered.

从上面的试验可以发现,虽然rebuild index online在执行期间只持有模式2的TM锁,不会阻塞DML操作,但在操作的开始和结束阶段,是需要短暂的持有模式为4的TM锁的,这段会阻塞表上的所有DML操作。我们在做rebuild index online的时候,一定要在

开始和结束阶段观察系统中是否有长事务的存在,对于并发量较大的系统,最严重的后果,可能在这两个关键点导致数据库产生大量锁等待,系统负载飙升,甚至宕机。

参考文档:http://www.ningoo.net/html/2008/lock_mechanism_of_rebuild_index_online.html