绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
外键约束的lock测试,典型的enq: TM -contention等待根因
2020-09-28 16:05:18

建表语句

CREATE TABLE DEPT
(
deptno NUMBER CONSTRAINT pk_dept PRIMARY KEY,
dname VARCHAR2(10)
);

CREATE TABLE EMP
(
deptno NUMBER(2) CONSTRAINT fk_deptno REFERENCES dept(deptno),
ename VARCHAR2(20)
);

查询主外键关系,主表DEPT得主键是DEPTNO,子表EMP得外键是deptno,reference主表得deptno.
column owner_name format a10
column table_name format a25
column key_name format a15
column referencing_table format a15
column foreign_key_name format a15

SELECT a.owner owner_name,
a.table_name table_name,
a.constraint_name key_name,
b.table_name referencing_table,
b.constraint_name foreign_key_name
FROM user_constraints a,
user_constraints b
WHERE a.constraint_name = b.r_constraint_name
AND b.constraint_type = 'R'
ORDER BY 1, 2, 3, 4;

OWNER_NAME TABLE_NAME KEY_NAME REFERENCING_TAB FOREIGN_KEY_NAME
---------- --------------------- --------------- --------------- ----------------
SCOTT DEPT PK_DEPT EMP FK_DEPTNO

没有创建索引时
column table_name format a25
SELECT object_id,
object_name
FROM dba_objects
WHERE object_name IN ('EMP','DEPT')
AND owner = 'SCOTT';

OBJECT_ID OBJECT_NAME
---------- -------------------------
13033 DEPT
13035 EMP

查询锁情况
SQL> INSERT INTO DEPT VALUES (1, 'COSTCENTER');
SQL> COMMIT;
SQL> INSERT INTO EMP VALUES (1, 'SCOTT');
SQL> SELECT sid, type, id1, id2,
lmode, request, block
FROM v$lock
WHERE sid IN
(SELECT sid FROM v$session WHERE audsid = userenv('SESSIONID')
);

SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
15 TX 589839 56552 6 0 0
15 TM 13035 0 3 0 0
15 TM 13033 0 3 0 0
此时仅仅向子表中插入一条数据,主表和子表都需要 Lmode=3的锁,即row exclusive lock

下面对主表操作DML
SQL> update dept set deptno = 1; <
SQL> SELECT SID,TYPE,ID1,ID2,LMODE,REQUEST,BLOCK FROM v$LOCK
where sid in (select sid from v$session where audsid = userenv('SESSIONID'));
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
15 TX 589839 56552 6 0 0
15 TM 13033 0 3 0 0
操作主表时,主表有锁,而子表没有锁。

外键有索引时,操作子表
SQL> create index ind_emp on emp (deptno, ename);
SQL> insert into DEPT values (1, 'COSTCENTER');
SQL> commit;
SQL> insert into EMP values (1, 'SCOTT');

SQL> SELECT SID,TYPE,ID1,ID2,LMODE,REQUEST,BLOCK FROM v$LOCK
where sid in (select sid from v$session where audsid = userenv('SESSIONID'));

SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
15 TX 393232 54853 6 0 0
15 TM 13035 0 3 0 0
15 TM 13033 0 2 0 0
此时主表持有Row share lock LMODE=2,而子表持有row exclusive lock

DML子表
SQL> update DEPT set deptno = 1;

1 row updated.

SQL> SELECT SID,TYPE,ID1,ID2,LMODE,REQUEST,BLOCK FROM v$LOCK
where sid in (select sid from v$session where audsid = userenv('SESSIONID'));

SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
15 TX 589839 56552 6 0 0
15 TM 13035 0 2 0 0
15 TM 13033 0 3 0 0

此时主表row exclusive lock (LMODE=3) 子表持有 row share lock LMODE=2

所以需要再子表的外键创建索引一防止enq:TM-contention的等待,这是一个队列,必须排队,造成SQL的缓慢感觉是夯住了。


分享好友

分享这个小栈给你的朋友们,一起进步吧。

Oracle运维新鲜事-技术与管理各占半边天
创建时间:2020-08-04 11:34:57
本技术栈旨在分享技术心得,运维趣事,故障处理经验,调优案例,故障处理涉及集群,DG,OGG,大家生产中遇到的问题基本都会囊括了,我会发布生产库遇到的故障,希望在交流中互助互益,共同提高,也希望大家讨论,如果您有生产中遇到的集群问题,也可以在这里提出来,一起讨论,现实中也帮助不少同学解决了生产库的故障。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • Abraham林老师
    栈主
  • 小雨滴
    嘉宾
  • hawkliu
    嘉宾
  • u_97a59a25246404
    嘉宾

小栈成员

查看更多
  • 栈栈
  • dapan
  • 小菜鸟___
  • hwayw
戳我,来吐槽~