ORACLE-锁模式

锁模式

锁描述

解释

SQL操作

 

0

none

 

 

 

 

NULL

Select

 

1

 

 

 

 

2

SS(Row-S)

行级共享锁,其他对象只能查询这些数据行

Select for update

lock table t1 in row share mode;

lock table t1 in share update mode;

允许对 该对象做DML操作

3

SX(Row-X)

行级排它锁,在提交前不允许做DML操作

InsertUpdateDelete

lock table t1 in row exclusive mode;

 

4

S(Share)

共享锁

Create index

lock table t1 in share mode;

 

5

SSX(S/Row-X)

共享行级排它表级锁

lock table t1 in share row exclusive mode;

 

6

X(Exclusive)

排它锁

Alter tableDrop ableDrop indexTruncate table

lock table t1 in exclusive mode;

 

 

知道一般情况下alter index rebuild online不会堵塞DML操作,那又是为什么呢。正好闲着没事做,就试着从锁上去找原因。

 

在这过程中写了个文档,和大家一起分享下对oracle几种锁模式的理解。

 

一.几种锁模式的描述

 

在ORACLE动态性能视图v$locklmode有以下几种类型(http://docs.oracle.com/cd/B19306_01/server.102/b14237/dynviews_1147.htm#i1407629 ):

 

0 - none

1 - null (NULL)

2 - row-S (SS)

3 - row-X (SX)

4 - share (S)

5 - S/Row-X (SSX)

6 - exclusive (X)

 

这里的描述比较模糊,但是在对lock table语句解释中可以找到相对应的详细解释(http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9015.htm#i2064405

 

1.ROW SHARE  

ROW SHARE permits concurrent access to the locked table but prohibits users from locking the entire table for exclusive access. ROW SHARE is synonymous with SHARE UPDATE, which is included for compatibility with earlier versions of Oracle Database.

 

ROW SHARE模式允许同时访问被锁定的表,但是禁止用户以排他方式锁定整个表。ROW SHARESHARE UPDATE相同,只是为了兼容早期的ORACLE版本。对应lmode2row-S (SS)

 

实验:but prohibits users from locking the entire table for exclusive access.

 

SID:285

SQL> lock table test_objects in row share mode;

 

Table(s) Locked.

 

SID:267

SQL> lock table test_objects in exclusive mode;

此时操作被锁。 对象被 添加 排它锁 之前,不可以被添加任何锁!!!

 

SID:294(用来查看当前的锁信息)

SQL> select * from v$lock where sid in (285,267);

ADDR     KADDR           SID TYPE          ID1        ID2      LMODE    REQUEST  CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ---------- ---------- ----------

42A87604 42A8761C        285 TM          72142          0          2          0  105          1

      

42A876B0 42A876C8        267 TM          72142          0          0          6  45          0

 

这里SID285TM2阻塞了SID267TM6

 

2.ROW EXCLUSIVE  

ROW EXCLUSIVE is the same as ROW SHARE, but it also prohibits locking in SHARE mode. ROW EXCLUSIVE locks are automatically obtained when updating, inserting, or deleting.

ROW EXCLUSIE类似于ROW SHARE模式,但是不能应用在SHARE模式中。当update,insert,delete发生时,ROW EXCLUSIVE会自动获得。对应lmode3row-X (SX)

 

针对这里的描述做两个实验:

实验1but it also prohibits locking in SHARE mode

 

SID:285

SQL>  lock table test_objects in share mode;

 

Table(s) Locked.

 

SID:267

SQL> lock table test_objects in  row exclusive mode;

 

SID:294

 

SQL> select * from v$lock where sid in (285,267);

ADDR     KADDR           SID TYPE          ID1        ID2      LMODE    REQUEST   CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ----------       ---------- ----------

42A87604 42A8761C        285 TM          72142          0          4          0  651          1

42A876B0 42A876C8        267 TM          72142          0          0          3  105          0

 

这里可以看到SID285TM4阻塞了SID267TM3

 

实验2

ROW EXCLUSIVE locks are automatically obtained when updating, inserting, or deleting.

当执行 update/ insert/ delete 操作的时候,会自动获取 行级排它锁

 

SID:285

SQL> update test_objects set object_id=1231 where id=23423;

 

1 row updated.

 

SID:294

SQL> select * from v$lock where sid in (285,267);

ADDR     KADDR           SID TYPE          ID1        ID2      LMODE    REQUEST    CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ----------

42A87604 42A8761C        285 TM          72142          0          3          0  6          0

42B58AFC 42B58C18        285 TX         458773       6086          6          0  6          0

 

SID285做了修改而没有commit或者rollback时,这里有两个锁,其中一个就是TM3的。 其中 ID1=458773是数据库中 数据字典,不用理会

 

3.SHARE SHARE

permits concurrent queries but prohibits updates to the locked table.

SHARE允许同时查询,但是禁止更新被锁定的表。对应lmode4share (S)

实验:but prohibits updates to the locked table

SID:285

SQL>  lock table test_objects in share mode;

 

Table(s) Locked.

 

SID:267

SQL> update test_objects set object_id=1231 where id=23423;

 

此时操作被阻塞

 

SID:294

SQL> select * from v$lock where sid in (285,267);

ADDR              KADDR             SID    TYPE          ID1          ID2      LMODE      REQUEST  CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ----------   ---------- ----------

42A87604    42A8761C        285     TM          72142          0          4                  0                28          1

42A876B0   42A876C8         267     TM          72142          0          0                  3                6          0

 

这里SID285TM4阻塞了SID267TM3

 

4.SHARE ROW EXCLUSIVE  

SHARE ROW  EXCLUSIVE is used to look at a whole table and to allow others to look at rows in the table but to prohibit others from locking the table in SHARE mode or from updating rows.

SHARE ROW EXCLUSIVE模式用于查看整个表,它允许其他session查看表中的行,但是不允许添加SHARE模式的锁。对应lmode5S/Row-X (SSX)

 

实验:but to prohibit others from locking the table in SHARE mode or from updating rows(根据上面ROW EXCLUSIVE中的实验,修改数据本来就会要对整个表添加一个TM3的锁)

SID:285

SQL> lock table test_objects in  share row exclusive  mode;

 

Table(s) Locked.

 

SID:267

SQL> lock table test_objects in  share  mode;

 

该操作被阻塞

 

SID:294

SQL> select * from v$lock where sid in (285,267);

ADDR               KADDR             SID    TYPE          ID1           ID2       LMODE    REQUEST  CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ----------   ---------- ----------

42A87604     42A8761C         285    TM          72142          0            5                   0              24             1

42A876B0     42A876C8         267    TM          72142          0            0                   4              3                0

 

这里SID285TM5阻塞了SID267TM4

 

5.EXCLUSIVE  

EXCLUSIVE permits queries on the locked table but prohibits any other activity on it.

EXCLUSIVE模式允许查询被锁表上的数据,但是禁止任何其他任何活动(这里我理解是禁止添加其他任何模式的锁)。对应lomde6exclusive (X)

经过类似的实验也证实了EXCLUSIVE确实会阻塞任何一种模式的锁,当然这其中也包括EXCLUSIVE

 

总结一下上面提到的堵塞的几种情况:

lmode2--->lmode6

lmode4--->lmode3

lmode5--->lmode4

lmode6--->所有的

 

二.几种实际情况的锁堵塞

 

1.DML操作

SID:285

SQL>  update test_objects set object_id=1231 where id=23423;

 

1 row updated.

 

SID:267

SQL> delete from test_objects where id=23423;

 

SID:294

SQL> select * from v$lock where sid in (285,267);

ADDR     KADDR           SID TYPE          ID1        ID2      LMODE    REQUEST   CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ----------  ---------- ----------

    

43A53A94 43A53AA8        267 TX         327692       7824          0          6   3          0

42A87604 42A8761C        285 TM          72142          0          3          0     24          0

42A876B0 42A876C8        267 TM          72142          0          3          0   3          0

42B58AFC 42B58C18        285 TX         327692       7824          6          0   24          1

 

这里可以看到SID285TM3并没堵塞SID267TM3,这里真正发生堵塞的是TX6

这里还有一个锁定对象的问题。上面两个TM3的锁针对的对象是object_id72142的表,既然描述是类似行共享,自然是不会堵塞的。而两个TX6的锁针对的对象可以理解成表中的行,在这些行上添加EXCLUSIVE锁(lmode6exclusive (X) )自然是会堵塞其他的EXCLUSIVE锁的。

 

解决这种类型的锁堵塞当然就是在代码中尽早commit结束事务。很多地方都写到尽早commit可以提高运行效率,这里所指的是释放锁(特别是lmode6EXCLUSIVE锁)减少堵塞,以提高并发性。(不是以减少数据的量来提高效率的,事实上不管多大的数据量,一个commit的过程都是很""的,具体可以参考Thoms的那本ORACLE体系结构的书)

 

2.DDL操作

alter index ... rebuild堵塞DML操作

 

SID:285

SQL> alter index IDX_TEXT_OBJECT_ID rebuild;

 

SID:267

update test_objects set object_id=1231 where id=2342;

 

SID:294

SQL> select * from v$lock where sid in (285,267);

ADDR     KADDR           SID TYPE          ID1        ID2      LMODE    REQUEST  CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- -------------------- ----------

43A53A94 43A53AA8        285 DL          72142          0          3          0  3          0

43A53B4C 43A53B60        285 DL          72142          0          3          0  3          0

42A87604 42A8761C        285 TM          72142          0          4          0  3          1

42A876B0 42A876C8        267 TM          72142          0          0          3  2          0

 

SID285TM4(SHARE)堵塞了SID267TM3(ROW EXCLUSIVE),就如上面提到的ROW EXCLUSIVE is the same as ROW SHARE, but it also prohibits locking in SHARE mode.

 

那alter index ... rebuild online为什么不会堵塞DML操作呢

 

SID:285

SQL> alter index IDX_TEXT_OBJECT_ID rebuild online;

 

SID:267

SQL> update test_objects set object_id=1231 where id=2342;

 

1 row updated.

 

SID:294

SQL> select * from v$lock where sid in (285,267);

ADDR     KADDR           SID TYPE          ID1        ID2      LMODE    REQUEST  CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ---------- ---------- ----------

43A53A94 43A53AA8        285 DL          72142          0          3          0  9          0

43A53B4C 43A53B60        285 DL          72142          0          3          0  9          0

42A87604 42A8761C        285 TM          72142          0          2          0   6          0

42A876B0 42A876C8        285 TM          72325          0          4          0   6          0

42A8775C 42A87774        267 TM          72142          0          3          0   6          0

42B157D4 42B158F0        267 TX         458789       6090          6          0   6          0

 

6 rows selected.

 

这里可以看到SID285添加了两个DL3的锁(lmode3,ROW EXCLUSIVE),一个TM2(lmode2,ROW SHARE),还有一个TM4的锁(lmode4,SHARE)

SID267就和一般的update语句一样添加了一个TM3的锁和一个TX6的锁。

 

根据前面总结的:

lmode2--->lmode6

lmode4--->lmode3

lmode5--->lmode4

lmode6--->所有的

lmode3没问题。

lmode2堵塞lmode6,但是他们锁的对象不一样也没问题。

lmode4堵塞lmode3,虽然这里都是TM类型的,但是SID285TM4的对象是72325,而SIDTM3的对象是72142,所以也不会有问题的。(这里的72325其实是ORACLE创建的一个临时对象,对它上个lmode4的锁自然不会影响对目标表的操作)。

 

因为DDL的操作和DML不同,它没有显式的提交。一条语句完了就自动commit了,也不显示rollback的情况,而且执行过程中强行中断还有可能会有些意想不到的情况。所以在平时情况可以多去看看,什么样的DDL语句会加什么样的锁,当执行的时候也就知道当前情况下执行的这条DDL语句在持有锁的时候会有什么影响。

 

3.一个特别的情况

这里是一个在ITPUB上看到的帖子,标题是:alter index rebuild online引发的血案

http://www.itpub.net/thread-1445427-1-1.html

 

根据上面的实验,alter index rebuild online是不会阻塞DML操作的,那又为什么会引起血案呢:

 

他的情况是这样:一个大的事务一直在执行,没有提交,以后操作alter index rebuild online,再之后所有应用就都hang住了。

 

模拟的情况如下:

 

SID:285

SQL> update test_objects set object_id=1231 where id=2342;

 

1 row updated.

 

SID:267

SQL> alter index IDX_TEXT_OBJECT_ID rebuild online;

 

SID:154

SQL> update test_objects set object_id=1231 where id=234245;

 

查看锁的情况:

SQL> select * from v$lock where sid in (285,267,154) order by sid;

ADDR     KADDR           SID TYPE          ID1        ID2      LMODE    REQUEST    CTIME      BLOCK

-------- -------- ---------- ------ ---------- ---------- ---------- ----------

42A87808 42A87820        154 TM          72142          0          0          3   21          0

43A53B4C 43A53B60        267 DL          72142          0          3          0  216          0

43A53A94 43A53AA8        267 DL          72142          0          3          0  216          0

42A876B0 42A876C8        267 TM          72142          0          2          4    216          0

42A8775C 42A87774        267 TM          72328          0          4          0     214          0

42A87604 42A8761C        285 TM          72142          0          3          0  228          1

42B4D60C 42B4D728        285 TX         589868       7867          6          0  228          0

 

最先开始的SID285,持有两个锁,TM3TX6没有问题

然后SID267,两个DL3锁没问题,一个其他对象的TM4锁,也没有问题,但是还有另一个已经持有了TM2的锁的同时,还要求请求lmode4的锁

再往后的SID154TM3锁也没有得到

 

一位网友在他的BLOG上讲解原因:

"虽然rebuild index online在执行期间只持有模式2TM锁,不会阻塞DML操作,但在操作的开始和结束阶段,是需要短暂的持有模式为4TM锁的,这段会阻塞表上的所有DML操作。 "

源地址是:http://www.ningoo.net/html/2008/lock_mechanism_of_rebuild_index_online.html

根据前面的实验:lmode4--->lmode3,这样也就可以理解了

而且根据网友的实验,11g开始后面的那个DML(就是SID154)将不会再被阻塞。

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1606090>

 

 

 

rebuild index online的锁机制浅析

 

2008年09月28日 by NinGoo 2 Comments

一般都说,rebuild index online不阻塞DML操作,这是相对于rebuild index来说的,加上了online,只是在rebuild的期间不阻塞DML,但是在开始和结束阶段还是可能阻塞其他进程的DML的,要弄清楚到底是 阻塞还是不阻塞,何处阻塞,为什么阻塞,还是要从锁的角度来分析。本文实验环境为Oracle 10.2.0.4

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

我们知道,DML操作一般要加两个锁,一个是对表加模式为3的TM锁,一个是对数据行的模式为6的TX锁。只要操作的不是同一行数据,是互不阻塞的。但是rebuild index online在开始和结束的时候是需要对表加一个模式为4的TM锁的这个可以很容易通过实验观察到,实验中的测试表t是通过create table t as select * from all_objects生成,并且多次执行insert into t select * from t产生较多的数据,以便延迟rebuild的时间来观察系统中锁的情况:

session 1:

SQL> delete from t where object_id=28;

1 row deleted.

session 2:

SQL> alter index ix_t rebuild online;

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

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

SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
      1643 DL      10599          0          3          0
      1643 DL      10599          0          3          0
      1622 TM      10599          0          3          0
      1643 TM      10599          0          2          4
      1643 TM      10607          0          4          0
      1622 TX     655398       1361          6          0

 

从上面的结果可以知道,1622是session 1,1643是session 2,session 2一共出现了4个锁,两个DL锁,一个针对表tTM锁,一个是online rebuild index时需要的一个中间表的TM锁,中间表用于记录rebuild期间的增量数据,原理类似于物化视图日志,其object_id10607,这是 一个索引组织表(IOT),从这里我们也可以发现IOT的优点和适合的场合,这张中间表只有插入,不会有删除和修改操作,而且只有主键条件查询,正是 IOT最合适的场景:

SQL> select object_name,object_type from all_objects where object_id=10607;

OBJECT_NAME                    OBJECT_TYPE
------------------------------ -------------------
SYS_JOURNAL_10602              TABLE

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

TABLE_NAME                     IOT_TYPE
------------------------------ ------------
SYS_JOURNAL_10602              IOT

Session 2在请求一个模式为4的TM锁,模式4会阻塞这个表上的所有DML操作,所以这是再往这个表上执行DML也会挂起

session 3:

SQL> delete from t where object_id=46;

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

SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
      1643 DL      10599          0          3          0
      1643 DL      10599          0          3          0
      1622 TM      10599          0          3          0
      1643 TM      10599          0          2          4
      1643 TM      10607          0          4          0
      1627 TM      10599          0          0          3
      1622 TX     655398       1361          6          0

1627就是session 3,请求模式为3的TM锁无法获得,会话被阻塞。这是因为锁请求是需要排队的,即使session 3session 1是可以并发的,但由于session 2先请求锁并进入等待队列,或来的session 3也只好进入队列等待。所以如果在执行rebuild index online前长事务,并且并发量比较大,则一旦执行alter index rebuild online,可能因为长事务阻塞,可能导致系统瞬间出现大量的锁,对于压力比较大的系统,这是一个不小的风险。这是需要迅速找出导致阻塞的会话kill 掉,rebuild index online一旦执行,不可轻易中断,否则可能遇到ORA-08104

在session 1执行rollback,可以发现很短时间内session 3也正常执行完毕,说明session 2只有模式4的TM锁的时间很短,然后在rebuild online的进行过程中,对表加的是模式为2的TM锁,所以这段时间不会阻塞DML操作:

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

SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
      1643 DL      10599          0          3          0
      1643 DL      10599          0          3          0
      1643 TM      10599          0          2          0
      1643 TM      10607          0          4          0
      1627 TM      10599          0          3          0
      1627 TX     655392       1361          6          0

保持session 3的事务不提交,等待一段时间后,session 2始终无法完成操作,再观察系统中锁的情况,可以发现又发生了变化:

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

SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
      1643 DL      10599          0          3          0
      1643 DL      10599          0          3          0
      1643 TM      10599          0          2          4
      1643 TM      10607          0          4          0
      1627 TM      10599          0          3          0
      1643 TX     589852        258          6          0
      1627 TX     655392       1361          6          0
 

Session 2又开始在请求模式4的TM锁,被session 3阻塞!这是在session 1再执行DML操作,同样会被session 2阻塞,进入锁等待队列。

Session 1:

SQL>delete from t where object_id=11;

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

SID TY        ID1        ID2      LMODE    REQUEST
---------- -- ---------- ---------- ---------- ----------
      1643 DL      10599          0          3          0
      1643 DL      10599          0          3          0
      1622 TM      10599          0          0          3
      1643 TM      10599          0          2          4
      1643 TM      10607          0          4          0
      1627 TM      10599          0          3          0
      1643 TX     589852        258          6          0
      1627 TX     655392       1361          6          0

在session 3执行rollback或者commit以后,session 2和session 3都很快执行完毕。

从上面的试验可以发现,虽然rebuild index online在执行期间只持有模式2TM锁,不会阻塞DML操作,但在操作的开始和结束阶段,是需要短暂的持有模式为4TM锁的,这段会阻塞表上的所 DML操作。我们在做rebuild index online的时候,一定要在开始和结束阶段观察系统中是否有长事务的存储,对于并发量较大的系统,最严重的后果,可能在这两个关键点导致数据库产生大量 锁等待,系统负载飙升,甚至宕机。

 

源文档 <http://www.ningoo.net/html/2008/lock_mechanism_of_rebuild_index_online.html>

 

 

 

创建时间:2022-03-30 20:54
浏览量:0