目录
3.4 执行Direct/Parallel Load工作时… 6
执行DML期间,为防止对与DML 相关的对象进行修改,执行DML的进程必须对该表获得TM锁。若在获取TM锁的过程中发生争用,则等待enq:TM-contention 事件。
TM锁其用途虽然十分明确,但是准确的概念及定义方面有容易混淆的一面。例如,Oracle的概念手册上,关于锁的分类说明如下:
以上说明可能让大家以为存在DML锁和DDL锁这两个锁,给大家带来混乱。实际上,DML锁和DDL锁只是为了合理分配锁而赋予的名称,请注意这一点。
DML锁实际上与TM锁一致。DML锁可以通过DBA_DML_LOCKS视图观察,这个视图的作用是从V$LOCK视图上筛选出锁类型为TM 的。数据库上允许的TM锁数量,可以利用DML_LOCKS参数指定。若将DML_LOCKS参数值设为0,则对于表无法获得TM锁。这时,Oracle为了保障表定义被保护,对于表根本上不允许DDL操作。因此,即便不获得TM锁,也允许修改表的特定行。如OPS环境下,为了减少在全局范围内获得TM锁过程中发生的附加资源消耗,有时也将DML_LOCKS值修改为0。
DDL锁实际上与library cache lock一致。DDL锁可以通过DBA_DDL_LOCKS视图观察,这个视图实际上起到加工X$KGLLK视图后显示的作用。DDL锁除DBA_DDL_LOCKS视图之外,还可以通过X$KGLLK,DBA_KGLLOCK等视图观察。
对于表,普通DML语句以Sub-Exclusive(SX)模式获得TM锁。Sub-Exclusive模式之间存在共享性,所以多个会话可以对相同的表执行DML。已执行DML 的会话对于表,以Sub-Exclusive模式获得TM锁,对于已修改的数据以独占(Exclusive)模式获得TX锁。
如下所示,可以通过V$LOCK视图,观察执行DML的会话以何种模式获得了哪些锁。
SQL> update test set id = 1 where rownum = 1;
… SQL> exec print_table(‘select * from v$lock where sid = 148’);
ADDR : C0000000ED2663D0 KADDR : C0000000ED2663F8 SID : 148 TYPE : TM ID1 : 54679 ID2 : 0 LMODE : 3 REQUEST : 0 CTIME : 67 BLOCK : 0 —————– ADDR : C0000000ED2DB7F8 KADDR : C0000000ED2DB980 SID : 148 TYPE : TX ID1 : 4718594 ID2 : 439 LMODE : 6 REQUEST : 0 CTIME : 67 BLOCK : 0 |
对于Object ID 54679(ID1)相应的对象,可以确认正在以Sub-Exclusive(3)模式获得TM锁。TM锁的ID1相当于表的Object ID。因此结合DBA_OBJECTS,就可以判断TM锁对应的表。因为Sub-Exclusive模式之间存在共享性,所以DML之间不发生围绕TM锁的争用,enq:TM-contention等待也不会发生。一般发生TM锁争用的情况如下:
P1 : Enqueue信息
P2 : Object#
P3 : Table/Partition信息
与enqueue等待事件相同。最大等待时间为3秒。若没有获取TM锁直等到到获取等待。
Oracle 9i之前,没有索引的外键列是TM锁争用的主要原因。Oracle 9i之前版本上,子表的外键列没有索引的状态下,若父表的键(Key)被修改,则对子表应该以共享(Shared)模式或Shared-Sub-Exclusive模式获得TM锁。已获得的TM锁一直拥有到父表修改键的事务结束为止(提交或回滚),因此经常发生性能严重下降的现象。但是从Oracle 9i开始,算法大幅得到改善,不再发生类似的争用现象。若还在使用Oracle 9i之前版本,则需要养成在外键列创建索引的习惯。
对于事务正运行的表,基本上不可能执行DDL。因此,这时不会发生争用引起的性能问题,接下来看一个具体例子。
会话A:
SQL> update test set id = 1 where rownum = 1; |
会话 B:
SQL> alter table test add ID2 number;
alter table test add ID2 number * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified |
对于已完成Update但还没有提交的表,不可能执行DDL。相反,对于正执行DDL的表执行DML时,可能发生TM锁争用。对于特定进程的表创建索引时,对于表在创建索引期间以共享(Shared)模式获得TM锁。
SQL> create index big_objects_idx_test
on big_objects(owner,object_name,object_id); ß 查看创建索引的期间以什么方式获取TM锁。 SQL> exec print_table(‘select * from v$lock where sid = 148’); … ADDR : C0000000ED2663D0 KADDR : C0000000ED2663F8 SID : 148 TYPE : TM ID1 : 52318 ID2 : 0 LMODE : 4 <– 共享模式 REQUEST : 0 CTIME : 3 BLOCK : 0 … |
利用TM锁的ID1,可获得表名BIG_OBJECTS。LMODE值是4,表示共享(Shared)模式。即,create index语句对于表big_objects,以共享模式获得TM锁。问题在于,对这个表执行DML的会话,应该以Sub-Exclusive模式获得TM锁。因为共享模式和Sub-Exclusive模式没有共享性,所以执行DML的会话等到DDL 执行结束为止时,才发生enq:TM-contention等待事件。减少DDL引起的TM锁争用的方法如下:
若对于数据多的表执行不当的DDL,则访问此表的所有DML 会话都会陷入等待状态,可能发展至故障状态。通过合理的管理,从根本上防止才是最好的方法。
执行DDL 时,最好使用Online选项。随着Oracle 版本升级,Online状态下可执行的DDL逐步增加。大部分普通DDL上,可以使用Online选项。例如,利用Online选项执行create index命令时,不是以共享模式,而是以Sub-Shared(SS)模式获得TM锁的。因为Sub-Shared 模式和Sub-Exclusive模式之间有共享性。所以在创建索引的过程中,可以执行DML。即,不会发生enq: TM-contention等待,接下来看一下例子。
会话A:(SID=148)
SQL> create index big_objects_idx_test111 on
big_objects(secondary, generated, temporary, status, timestamp, last_ddl_time) online; 以Online选项创建 |
会话B:
SQL> exec print_table(‘select * from v$lock where sid = 148’);
… ADDR : C0000000ED2663D0 KADDR : C0000000ED2663F8 SID : 148 TYPE : TM ID1 : 52318 ID2 : 0 LMODE : 2 <– Sub-Shared模式 REQUEST : 0 CTIME : 1 BLOCK : 0 … |
使用Parallel DDL将DDL的执行速度最大化。对拥有大量数据的表执行DDL时,若恰当使用Parallel 选项,可将DDL本身性能最大化,而且同时使用Nologging选项也比较好。如果提升了DDL执行速度,TX锁争用引起的等待时间相应地也会下降。
利用Lock table …语句有意获取TM锁时可能发生TM锁争用。
会话A: (SID=148)
SQL> update test set id=1 where rownum=1; |
会话B:(SID=150)
SQL> lock table test in exclusive mode;
… Wait … |
如上所示,会话A上因update以Sub-Exclusive 模式拥有TM锁的状态下,会话B利用lock table 命令,试图以独占(Exclusive)模式获得TM锁时,如果发生争用,则等待enq:TM-contention事件。
发生TM锁引起的争用时,收集锁拥有者(lock holder)在会话上执行的SQL语句尤为重要。发生TM锁的情况非常多样,因此没有SQL语句,就很难作出准确判断的情况较多。引发问题的SQL语句是Lock table …语句,因此如果发生大量的TM锁争用,可以通过对应用程序的适当修正解决争用。与其为了同步对整个表上锁,不如考虑使用DMBS_LOCK程序包或使用select … for update等,减少锁范围的方法。
INSERT /*+ APPEND */ INTO…或SQL*Loader的direct path load之类的部分功能,对于相应表以Exclusive 模式获得TM锁。Direct load工作不经过SGA,而是直接写入到数据文件里,所以在执行工作期间不允许对表进行任何修改。总之,以独占模式获得TM锁,对于表不允许发生任何修改,这点应该得到保障,工作才能得以继续。
Direct load 工作在执行期间,不允许对于表执行任何DDL或DML。因此事务多的时刻执行Direct load工作时,需要确认TM锁争用是否可能引发问题。将SQL*Loader利用parallel模式执行时,对表以共享模式获取TM锁。因此,此种情况下也不会允许其他会话上的DDL 或DML。
Leave a Reply
Be the First to Comment!