联系:QQ(5163721)
标题:insert 的enq: TM – contention的情况-1 —–对有主外键关系的表的操作
作者:Lunar©版权所有[文章允许转载,但必须以链接方式注明源地址,否则追究法律责任.]
insert 的enq: TM – contention的情况-1 —–对有主外键关系的表的操作
insert 的enq: TM – contention的情况-2 —–只有主键约束无子表的情况
####################################################################################
总结1 :当外键无索引时
1,对子表的insert操作所在的事务没有完成前,对于父表的DML操作(INSERT/UPDATE/DELETE)都会因为不能获得对子表的TM锁而出现enq: TM – contention。
2,在总结1的基础上,如果又有了对子表的insert(我没有测试,但是我怀疑这里如果改成对子表的update和delete,也是相同道理……).
那么这个对子表的insert同样被阻塞,等待事件也是 enq: TM – contention。
3,对父表的insert会阻塞对父表的delete。同样的道理,此时对父表的insert也阻塞对父表的update pk操作。
####################################################################################
SQL> conn lunar/lunar
Connected.
SQL> CREATE TABLE DEPT
2 (
3 deptno NUMBER CONSTRAINT pk_dept PRIMARY KEY,
4 dname VARCHAR2(10)
5 );
CREATE TABLE EMP
(
deptno NUMBER(2) CONSTRAINT fk_deptno REFERENCES dept(deptno),
ename VARCHAR2(20)
);
Table created.
SQL> SQL> 2 3 4 5
Table created.
SQL>
SQL> select index_name from dba_indexes where OWNER='LUNAR';
INDEX_NAME
------------------------------
PK_DEPT
Elapsed: 00:00:00.21
SQL>
SQL> insert into DEPT values (1, 'COSTCENTER');
1 row created.
SQL> insert into EMP values (1, 'SCOTT');
1 row created.
SQL>
SQL> set linesize 200
SQL> set pages 999
SQL> set timing on
SQL> /
OWNER_NAME TABLE_NAME KEY_NAME REFERENCING_TAB FOREIGN_KEY_NAM
---------- ------------------------- --------------- --------------- ---------------
LUNAR DEPT PK_DEPT EMP FK_DEPTNO
Elapsed: 00:00:01.07
SQL>
SQL> column table_name format a25
SQL> SELECT object_id,
2 object_name
FROM dba_objects
3 4 WHERE object_name IN ('EMP','DEPT')
5 AND owner = 'LUNAR';
OBJECT_ID OBJECT_NAME
---------- --------------------------------------------------------------------------------------------------------------------------------
1062788 DEPT
1062790 EMP
Elapsed: 00:00:00.08
SQL>
#########################################################
当没有索引的时候:
#########################################################
测试1, 在子表发生:Insert,然后在父表上有update操作
SQL> rollback; Rollback complete. Elapsed: 00:00:00.00 SQL> select * from dept; no rows selected Elapsed: 00:00:00.02 SQL> select * from emp; no rows selected Elapsed: 00:00:00.01 SQL>
Session 1: 对子表进行insert,不commit时:
SQL> INSERT INTO DEPT VALUES (1, 'COSTCENTER');
1 row created.
Elapsed: 00:00:00.00
SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
SQL> INSERT INTO EMP VALUES (1, 'SCOTT');
1 row created.
Elapsed: 00:00:00.00
SQL> SELECT sid, type, id1, id2,
2 lmode, request, block
3 FROM v$lock
4 WHERE sid IN
5 (SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID') );
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
321 AE 884349 0 4 0 0
321 TM 1062790 0 3 0 0
321 TM 1062788 0 3 0 0
321 TX 65546 71036 6 0 0
Elapsed: 00:00:00.55
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
321
Elapsed: 00:00:00.01
SQL>
这是,我们看到,该回话在主表(1062788 DEPT)和子表(1062790 EMP)上都分别持有了 exclusive lock(LMODE=3)锁
同时,该回话还持有一个tx锁(在子表 emp上)
另开一个会话,观察锁:
SQL> select substr(type,1,2) type,substr(name,1,30) name ,substr(description,1,40) description 2 from v$lock_type 3 where substr(type,1,2)='AE' 4 ; TYPE NAME -------- ------------------------------------------------------------------------------------------------------------------------ DESCRIPTION ---------------------------------------------------------------------------------------------------------------------------------------------------------------- AE Edition Lock Prevent Dropping an edition in use Elapsed: 00:00:00.01 SQL>
Session 2 : 然后,我们在父表做DML操作update:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
220
SQL> update dept set deptno = 1;
...hang...
Session 3: 检查锁的变化
SELECT sid, type, id1, id2, lmode, request, block
FROM v$lock
WHERE sid IN (220,321)
ORDER BY SID;
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
220 TM 1062790 0 0 4 0
220 TM 1062788 0 3 0 0
220 AE 884349 0 4 0 0
321 TX 65546 71036 6 0 0
321 TM 1062790 0 3 0 1 --------blocker
321 TM 1062788 0 3 0 0
321 AE 884349 0 4 0 0
SPID SID SERIAL# STATUS
------------------------ ---------- ---------- --------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID EVENT STATUS
------------- ---------------------------------------------------------------- --------
12456 220 20401 ACTIVE
update dept set deptno = 1
4xjxb3twbayrj enq: TM - contention ACTIVE
SQL> select * from v$lock where block=1;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
00007F6C85314EE0 00007F6C85314F40 321 TM 1062790 0 3 0 253 1
Elapsed: 00:00:00.07
SQL>
这是我们看到,Session 2 在子表(1062790 EMP)上请求LMODE=4,并在主表(1062788 DEPT)上持有等待:enq: TM – contention
这是很清晰,有blocker了,也就是Session 1(SID 321),此时该回话正在对子表(1062790 EMP)进行插入操作
##################################
换句话说,当外键无索引时,对子表的insert操作,会造成对父表的更新操作的阻塞。
##################################
Session 4 更新父表:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
116
SQL> update dept set deptno = 1 where deptno = 2;
.....HANG.....
Session 3: 观察
SELECT sid, type, id1, id2, lmode, request, block
FROM v$lock
WHERE sid IN (220,321,116) AND TYPE!='AE'
ORDER BY SID,type,ID1;
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
116 TM 1062788 0 3 0 0
116 TM 1062790 0 0 4 0
220 TM 1062788 0 3 0 0
220 TM 1062790 0 0 4 0
321 TM 1062788 0 3 0 0
321 TM 1062790 0 3 0 1
321 TX 65546 71036 6 0 0
SPID SID SERIAL# STATUS
------------------------ ---------- ---------- --------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID EVENT STATUS
------------- ---------------------------------------------------------------- --------
12602 116 64289 ACTIVE
update dept set deptno = 1 where deptno = 2
2ha4z6qzxngj1 enq: TM - contention ACTIVE
12456 220 20401 ACTIVE
update dept set deptno = 1
4xjxb3twbayrj enq: TM - contention ACTIVE
SQL> select * from v$lock where block=1;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
00007F6C85314EE0 00007F6C85314F40 321 TM 1062790 0 3 0 386 1
这是我们看到,session 4(sid 116)遵循了跟session 220同样的所规律
这是我们在Session 1中执行commit,在Session 3中观察:
Session 1: SQL> commit; Commit complete. Elapsed: 00:00:00.00 SQL>
可以看到Session 2和Session 4都完成了update:
Session 2:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
220
SQL> update dept set deptno = 1;
1 row updated.
SQL>
Session 4:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
116
SQL> update dept set deptno = 1 where deptno = 2;
0 rows updated.
SQL>
Session 3:
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
116 TM 1062788 0 3 0 0 -------session 4获得了父表的update加LMODE=3的TM锁
220 TM 1062788 0 3 0 0 -------session 2也获得了父表的update加LMODE=3的TM锁
220 TX 1048603 29682 6 0 0
此时的等待事件:
SQL> select sid,event from v$session_wait where sid in (220,321,116);
SID EVENT
---------- ----------------------------------------------------------------
116 SQL*Net message from client
220 SQL*Net message from client
321 SQL*Net message from client
Elapsed: 00:00:00.00
SQL>
这里我们看到,当外键无索引时,对子表的insert操作,会造成对父表的更新操作的阻塞,该阻塞直到子表的insert事务结束,才自动释放。
测试2, 在子表发生:Insert,然后在父表上有update操作,然后再有一个会话对子表做insert
重复上面的操作,不对session 1进行commit时,再开一个窗口(Session 5)对子表做insert
SQL> conn lunar/lunar
Connected.
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
222
SQL> INSERT INTO EMP VALUES (2,'LUNAR');
。。。。。hang。。。。。。。
这是我们看到,对于子表的insert语句被阻塞了。
在Session 3中观察:
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
116 TM 1062788 0 3 0 0
116 TM 1062790 0 0 4 0
220 TM 1062788 0 3 0 0
220 TM 1062790 0 0 4 0
222 TM 1062788 0 3 0 0
222 TM 1062790 0 0 3 0 --------session 220请求以LMODE=3的模式对子表加TM锁
321 TM 1062788 0 3 0 0
321 TM 1062790 0 3 0 1
321 TX 1310752 43053 6 0 0
SPID SID SERIAL# STATUS
------------------------ ---------- ---------- --------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID EVENT STATUS
------------- ---------------------------------------------------------------- --------
12602 116 64289 ACTIVE
update dept set deptno = 1 where deptno = 2
2ha4z6qzxngj1 enq: TM - contention ACTIVE
12456 220 20401 ACTIVE
update dept set deptno = 1
4xjxb3twbayrj enq: TM - contention ACTIVE
12766 222 49879 ACTIVE
INSERT INTO EMP VALUES (2,'LUNAR')
83wzmhc9kz5dp enq: TM - contention ACTIVE
这里我们看到:
1,当外键无索引时,对子表的insert操作,会造成对父表的更新操作的阻塞,该阻塞直到子表的insert事务结束,才自动释放。
2,如果对子表有insert操作,在这个insert所在事务没有commit之前,有对父表的update,那么接下来的对子表的inser会被阻塞
测试3:
在测试2的场景上,将session 2和session 4中的对父表的update执行Ctrl+C,然后分别改为INSERT 和delete 父表(dept)的操作,观察一下
Session 4:
SQL> update dept set deptno = 1 where deptno = 2; ^Cupdate dept set deptno = 1 where deptno = 2 * ERROR at line 1: ORA-01013: user requested cancel of current operation SQL> Session 2: SQL> update dept set deptno = 1; ^Cupdate dept set deptno = 1 * ERROR at line 1: ORA-01013: user requested cancel of current operation
Session 5 随之自动解锁,并报了正常的违反约束的错误:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
222
SQL> INSERT INTO EMP VALUES (2,'LUNAR');
INSERT INTO EMP VALUES (2,'LUNAR')
*
ERROR at line 1:
ORA-02291: integrity constraint (LUNAR.FK_DEPTNO) violated - parent key not
found
SQL>
在session 2中执行delete 父表的操作:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
220
SQL> delete from dept where deptno = 1;
..... HANG......
在session 3中观察:
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
220 TM 1062788 0 3 0 0
220 TM 1062790 0 0 4 0
321 TM 1062788 0 3 0 0
321 TM 1062790 0 3 0 1
321 TX 1310752 43053 6 0 0
SPID SID SERIAL# STATUS
------------------------ ---------- ---------- --------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID EVENT STATUS
------------- ---------------------------------------------------------------- --------
12456 220 20401 ACTIVE
delete from dept where deptno = 1
56m0bvac2yfkm enq: TM - contention ACTIVE
12766 222 49879 INACTIVE
INSERT INTO EMP VALUES (2,'LUNAR')
83wzmhc9kz5dp SQL*Net message from client INACTIVE
注意:
1,delete父表的操作被阻塞,依然是正在请求以LMODE=4的模式对子表(1062790 EMP)的TM锁
2,这里的sid 222中为非活动会话,当该回话执行了commit或者rollback后,这个Insert的“SQL*Net message from client”等待就会消失了。
测试4: 在测试3的场景上,继续session 4中的对父表做insert 的操作,观察一下
Session 4:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
116
SQL> INSERT INTO DEPT VALUES (2,'LUNAR');
。。。。。hang 。。。。。。。。。。
在Session 3观察:
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
116 TM 1062788 0 3 0 0
116 TM 1062790 0 0 3 0
220 TM 1062788 0 3 0 0
220 TM 1062790 0 0 4 0
321 TM 1062788 0 3 0 0
321 TM 1062790 0 3 0 1
321 TX 1310752 43053 6 0 0
SPID SID SERIAL# STATUS
------------------------ ---------- ---------- --------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID EVENT STATUS
------------- ---------------------------------------------------------------- --------
12602 116 64289 ACTIVE
INSERT INTO DEPT VALUES (2,'LUNAR')
g2dc3zwjr19hf enq: TM - contention ACTIVE
12456 220 20401 ACTIVE
delete from dept where deptno = 1
56m0bvac2yfkm enq: TM - contention ACTIVE
这里我们看到,虽然Session 4执行的是对父表的insert,session 2执行的是对父表的 delete,他们的表现跟update的表现都是相同的。
也就是说,对于子表的insert操作所在的事务没有完成前,对于父表的DML操作(INSERT/UPDATE/DELETE)都会因为不能获得对子表的TM锁而出现enq: TM – contention
测试5: 在测试4的基础上,我们在Session 1对做commit,完成对子表的insert操作,然后观察其他session:
Session 1:
SQL> INSERT INTO EMP VALUES (1, 'SCOTT'); 1 row created. Elapsed: 00:00:00.00 SQL> commit; Commit complete. Elapsed: 00:00:00.00 SQL>
Session 4:对父表的insert插入操作随着session 1的commit 自动解锁:
SQL> SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID');
SID
----------
116
SQL> INSERT INTO DEPT VALUES (2,'LUNAR');
1 row created.
SQL>
Session 2(SID 220):对父表的delete操作依然是hang的状态:
SQL> delete from dept where deptno = 1;
...HANG ...
在session 3观察:
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
116 TM 1062788 0 3 0 0
116 TM 1062790 0 3 0 1 ----------session 4(sid 116)是阻塞者了
116 TX 1310742 42713 6 0 0
220 TM 1062788 0 3 0 0 ----------session 2依然是刚才的状态
220 TM 1062790 0 0 4 0
220 TX 65567 71014 6 0 0
SPID SID SERIAL# STATUS
------------------------ ---------- ---------- --------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID EVENT STATUS
------------- ---------------------------------------------------------------- --------
12456 220 20401 ACTIVE
delete from dept where deptno = 1
56m0bvac2yfkm enq: TM - contention ACTIVE
也就是说,这里我们看到了,对父表的insert,阻塞了对父表的delete
——未完,待续—
