执行DML期间,为防止对与DML相关的对象进行修改,执行DML的进程必须对该表获得TM锁。若在获得TM锁的过程中发生争用,则等待enq: HW - contention 事件。
SQL> select name,parameter1,parameter2,parameter3 from v$event_name where name like 'enq: TM - contention';
NAME PARAMETER1 PARAMETER2 PARAMETER3
------------------------------ -------------------- -------------------- --------------------
enq: TM - contention name|mode object # table/partition
(注意:可能大家以为存在DML锁和DDL锁这两个锁,实际上,DML锁和DDL锁只是为了合理分配锁而赋予的名称。)
DML锁:data lock。执行DML时保护数据的锁。Row Lock(TX)保护特定行,Table Lock(TM)保护整个表,可以通过dba_dml_locks观察。这个视图的作用是从v$lock视图上筛选出锁类型为TM的。数据库上允许的TM锁数量,可以利用dml_locks参数指定。
DDL锁:data dictionary lock。保护User/Table/View/Procedure等定义,可以通过dba_ddl_locks观察。
一般发生TM锁争用的情况如下:
1、不当的DDL引起的TM锁争用
对于事务正运行的表,基本上不可能执行DDL。因此这时不会发生争用引起的性能问题。对于已经完成update但还没有提交的表,不可能执行DDL。相反,对于正在执行DDL的表执行DML时,可能发生TM锁争用。
若对于数据多的表执行不当的DDL,则访问此表的所有DML会话都会陷入等待状态,可能发展至故障状态。通过合理的管理,从根本上防止才是最好的方法。
执行DDL时,最好使用online选项。随着oracle版本升级,online状态下可执行的DDL逐步增加。
使用parallel DDL将DDL的执行速度最大化。对拥有大量数据的表执行DDL时,若恰当使用parallel选项,可将DDL本身性能最大化,而且同时使用nologging选项也比较好。
2、利用Lock table ...主动获取TM锁时
利用Lock table ...语句有意获取TM锁时可能发生TM锁争用。发生TM锁引起的争用,收集锁拥有着在会话上执行的SQL语句尤为重要。
3、执行Direct/Parallel Load工作时
INSERT /*+ APPEND */ INTO ...或SQL*Loader的direct path load之类的部分功能,对于相应的表以Exclusive模式获得TM锁。Direct load工作不经过SGA,而是直接写入到数据文件里,所以在执行工作期间不允许对表进行任何修改。Direct load工作在执行工作期间,不允许对于表任何DDL或DML。因此,事务多的时刻执行Direct load工作时,需要确认TM锁争用是否可能引发问题。将SQL*Loader利用Parallel模式执行时,对表以Shared模式获取TM锁。因此,此种情况下也不会允许其它会话上的DDL或DML。