外键字段上索引对锁的影响
子表的外键上如果不创建索引,就有可能导致死锁问题
scenario 1: 更新主表主键,子表外键无索引
1 | create table t_pri (id number,name varchar2(10)); |
session 1:
1 | XB@xb> select sid from v$mystat where rownum=1; |
session 2:
1 | XB@xb> select sid from v$mystat where rownum=1; |
session 3:
1 | XB@xb> select sid from v$mystat where rownum=1; |
查看锁信息:
1 | SYS@xb> @lock "sid in (41,56,62)" |
通过上面的结果可以看到,session2在更新主键的时候,子表外键字段上面没有索引,所以会对t_ref表请求一个TM级别的share锁,而优先的session1会话 正在对t_ref做insert的操作,已经在t_ref上加了一个TM级别的Row-X (SX)锁,与share锁是互相排斥,所以session2 hang住。session3对 t_ref做dml操作的时候,同样会请求TM级别的Row-X (SX)锁,则被session2所阻塞。
scenario 2: 删除主表行,子表on delete cascade
1 | XB@xb> alter table t_ref drop constraint fk_ref; |
session 1(sid:62):
1 | XB@xb> insert into t_ref values(1,'xb',10); |
session 2(sid:41):
1 | XB@xb> delete from t_pri where id=10; |
session 3(sid:56):
1 | XB@xb> insert into t_ref values(2,'lves',20); |
查看锁信息:
1 | SYS@xb> @lock "sid in (41,56,62)" |
这里看到session2请求的锁变成了TM级别的S/Row-X (SSX)锁,表示要先读取t_ref全表(share),然后更改部分行数据(SX)。因为外键上有’on delete cascade’,所以回滚session1以后才能继续执行
session 1(sid:62):
1 | XB@xb> rollback; |
session 2(sid:41):
1 | XB@xb> delete from t_pri where id=10; |
session 3(sid:56):
1 | XB@xb> insert into t_ref values(2,'lves',20); |
scenario 3: 更新主表主键,子表外键有索引
1 | XB@xb> create index idx_ref on t_ref(pri_id); |
session 1(sid:62):
1 | XB@xb> insert into t_ref values(1,'xb',10); |
session 2(sid:41):
1 | XB@xb> update t_pri set id=10,name='xb2' where id=10; |
此时session2 并未被堵塞。
Summary:
- 需要在所有的外键上建立索引,可以用以下语句查询
1 | select owner, |
- 更新主表尽量不要更新主键
外键字段上索引对锁的影响
https://www.xbdba.com/2018/11/14/foreign-key-noindex-lock/