外键字段未建索引引发的死锁
现象:一个很简单的程序在压力测试过程中发现死锁,查看trace文件,发现如下信息:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TM-0000627d-00000000 21 1062 SX SSX 22 1092 SX SSX
TM-0000627d-00000000 22 1092 SX SSX 21 1062 SX SSX
session 1062: DID 0001-0015-0000001E session 1092: DID 0001-0016-0005C757
session 1092: DID 0001-0016-0005C757 session 1062: DID 0001-0015-0000001E
Rows waited on:
Session 1092: no row
Session 1062: no row
而引发这个死锁的sql如下:
Current SQL Statement:
DELETE FROM TABLE WHERE COL = :B1
[@more@]
首先注意到的是Deadlock graph中的资源占有情况,可以看到两个session都hold了一个SZ类型的锁,同时在等待SSX类型的锁,而且引发的是一个删除语句,并且这个表是系统的一个关键表,大部分的表的外键都引用自此表的主键。因此猜测是碰到了外键引发的死锁。试验如下:
1、创建一个表,此表作为子表
SQL> create table fk_table as select * from user_objects;
Table created
2、创建一个表,此表作为父表
SQL> create table pk_table as select * from user_objects;
Table created
3、创建父表的主键
SQL> alter table PK_TABLE add constraint pk_pktable primary key (OBJECT_ID);
Table altered
4、创建子表的外键
SQL> alter table FK_TABLE add constraint fk_fktable foreign key (OBJECT_ID) references pk_table (OBJECT_ID);
Table altered
5、如下sql取自TOAD工具,用来显示数据库锁的信息
SELECT LK.SID,
SE.USERNAME,
SE.OSUSER,
SE.MACHINE,
DECODE(LK.TYPE,
'TX',
'Transaction',
'TM',
'DML',
'UL',
'PL/SQL User Lock',
LK.TYPE) LOCK_TYPE,
DECODE(LK.LMODE,
0,
'None',
1,
'Null',
2,
'Row-S (SS)',
3,
'Row-X (SX)',
4,
'Share',
5,
'S/Row-X (SSX)',
6,
'Exclusive',
TO_CHAR(LK.LMODE)) MODE_HELD,
DECODE(LK.REQUEST,
0,
'None',
1,
'Null',
2,
'Row-S (SS)',
3,
'Row-X (SX)',
4,
'Share',
5,
'S/Row-X (SSX)',
6,
'Exclusive',
TO_CHAR(LK.REQUEST)) MODE_REQUESTED,
TO_CHAR(LK.ID1) LOCK_ID1,
TO_CHAR(LK.ID2) LOCK_ID2,
OB.OWNER,
OB.OBJECT_TYPE,
OB.OBJECT_NAME,
LK.BLOCK,
SE.LOCKWAIT
FROM V$LOCK LK, DBA_OBJECTS OB, V$SESSION SE
WHERE LK.TYPE IN ('TM', 'UL')
AND LK.SID = SE.SID
AND LK.ID1 = OB.OBJECT_ID(+);
6、执行一个删除操作,这时候在子表和父表上都加了一个Row-S(SX)锁
delete from fk_table where object_id=94716;
delete from pk_table where object_id=94716;
7、执行另一个删除操作,发现这时候第二个删除语句等待
delete from fk_table where object_id=94702;
delete from pk_table where object_id=94702;
执行查询语句,得到锁信息如下:
857 DML Row-S (SS) None 107220 0 BILL TABLE PK_TABLE 0 00000000D555A0E8
872 DML Row-X (SX) None 107220 0 BILL TABLE PK_TABLE 0
857 DML Row-X (SX) S/Row-X (SSX) 107219 0 BILL TABLE FK_TABLE 0 00000000D555A0E8
872 DML Row-X (SX) None 107219 0 BILL TABLE FK_TABLE 1
可以看到session 857在请求一个SSX类型的锁,此时如果执行如下操作:
delete from pk_table where object_id=94716;
死锁马上发生,因为857 SESSION拿到了一个对FK_TABLE的行独占锁,并在请求一个表共享锁,而872 SESSION也拿到了一个FK_TABLE上的行独占锁,并请求一个表共享锁。此时两个session谁都不会释放独占锁,并同时请求表的共享锁,死锁由此引发。因为死锁引发的时候两个session不是在等待对数据行进行加锁,所以可以从trace文件中发现等待的行都为no row,同时可以看到两个session都hold了一个SX锁,并且都在等待SSX锁资源。同时trace文件中还记录了引发死锁的sql。
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TM-0001a2d3-00000000 16 872 SX SSX 20 857 SX SSX
TM-0001a2d3-00000000 20 857 SX SSX 16 872 SX SSX
session 872: DID 0001-0010-000F5EA0 session 857: DID 0001-0014-001D7407
session 857: DID 0001-0014-001D7407 session 872: DID 0001-0010-000F5EA0
Rows waited on:
Session 857: no row
Session 872: no row
Current SQL Statement:
delete from pk_table where object_id=94716
8、当对子表的外键列添加索引后,死锁被消除,因为这时删除父表记录不需要对子表加表级锁,这里不再做测试。
结论:曾经有人讨论过是否所有的数据库设计都应该遵守范式的规范,都把主外键关系建立起来。也有人反对这样做,因为这样复杂的关系在OLTP系统中可能会成为灾难,而提倡通过程序来保证数据的完整性,但程序发生bug导致数据不一致的情况时有发生。而且如果外键设置为级联删除,则不加索引的外键会使得对子表的记录删除走全表扫描。因此,对外键的使用还是要慎重!
btw:为什么删除子表记录的时候要加表级的共享锁呢?还有这个加锁好像只是一瞬间的,期待深入!!!
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25016/viewspace-923330/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/25016/viewspace-923330/
外键字段未建索引引发的死锁相关推荐
- [数据库03]-约束(唯一性-主键-外键/存储引擎/事务/索引/视图/DBA命令/数据库设计三范式
[数据库03]-约束(唯一性-主键-外键)/存储引擎/事务/索引/视图/DBA命令/数据库设计三范式 一.约束 1.1 唯一性约束(unique) 1.2 主键约束 1.3 外键约束 二.存储引擎 2 ...
- 三大范式,ER图,外键,视图,索引,触发器
目录 一.数据库三大范式 二.ER图和实例 2.1.什么是ER图: 2.2.ER图核心要素: 2.3.画ER图和数据建模 三.外键约束与级联操作 3.1.什么是外键? 3.2.什么是外键约束? 3.3 ...
- sqlserver怎么查看索引_Sql Server之旅——第六站 为什么都说状态少的字段不能建索引...
我们在学sqlserver的时候,大多教科书和前辈们都说状态少的字段不要建索引,由此带来的开销还不如不建索引,但是这句话有多少人真的知道,或者说有多少人真的对此有比较深刻的理解,而不是听别人道听途说. ...
- 为什么重复值高的字段不能建索引(比如性别字段等)
结论(以innodb为例) a.非聚簇索引存储了对主键的引用,如果select字段不在非聚簇索引内,就需要跳到主键索引(上图中从右边的索引树跳到左边的索引树),再获取select字段值 b.如果非聚簇 ...
- Sql Server之旅——第六站 为什么都说状态少的字段不能建索引
我们在学sqlserver的时候,大多教科书和前辈们都说状态少的字段不要建索引,由此带来的开销还不如不建索引,但是这句话有多少人真的知道,或者说有多少人真的对此有比较深刻的理解,而不是听别人道听途说. ...
- oracle外键有什么用,深入理解Oracle索引(20):外键是否应该加索引
先表明我的立场.我是绝对支持外键一定要加索引! 虽然在高版本的Oracle里.对这个要求有所降低.但依然有如下原因: ① 死锁 外键未加索引是导致死锁的最主要原因.因为 无论更新父表主键.或者删除一个 ...
- MySQL数据库基础(外键约束、添加索引)
文章目录 一.外键约束 1.外键概念 2.关联约束 3.添加与删除外键 4.集联删除 二.MySQL索引 1.创建唯一索引(三种方法) 2.索引查询 3.全文索引 4.联合索引 5.删除索引 一.外键 ...
- mysql 错误号1553 MySQL Cannot drop index needed in a foreign key constraint,外键也会创建索引
表 被参照表: | teacher | CREATE TABLE `teacher` (`id` varchar(20) NOT NULL,`name` varchar(255) DEFAULT NU ...
- day08 外键字段的增删改查 正向反向插叙概念 跨表查询 聚合查询与分组查询 F查询
day08 外键字段的增删改查 正向反向插叙概念 跨表查询 聚合查询与分组查询 F查询 昨日内容复习 自定义过滤器.标签.inclusion_tag 1.首先现在应用目录下创建名字为templatet ...
最新文章
- 《C#精彩实例教程》小组阅读10 -- C#属性与方法
- WebPack在多页应用项目中的探索
- 《重新认识你自己》八:与真实的自我相处
- Coding:就地合并两个排序数组
- JavaScript实现使用 BACKTRACKING 方法查找集合的幂集算法
- 我来说说java的NIO
- 使用 Log4Net 记录日志
- Orleans配置---持久化
- 依据imu姿态角计算z轴倾角_[姿态估计] DenseFusion详解
- 软件项目管理案例教程第4版课后习题第二章
- windows映射网络驱动器方法
- 弘玑Cyclone上榜36氪中国超自动化先锋企业
- 对PVP手游产品《王者荣耀》的一些思考
- 欧拉函数、费马定理、欧拉定理
- 解除360的系统压缩
- Java中的动态代理详解
- 100以内的所有质数的输出
- spring data JPA常用注解
- Jqgird 如何使用自带的search模块进行数据查询
- 单元格等于计算机日期,《excel表格怎样自动填写日期》 Excel单元格中自动获取当前日期与时间...
热门文章
- 22计算机考研上岸个人经验近万字分享(11408初试360分)
- python中复数的乘法_不一致的numpy复数乘法结果
- 机器学习项目实战——10决策树算法之动物分类
- DeiT:Training data-efficient image transformers distillation through attention
- oracle 表空间不足解决办法
- gcc利用-m32编译报错问题处理
- SPARK-SQL - group分组聚合api,agg()
- RT-Thread 4.1.0 特性解析之LIBC与POSIX
- 世界经典电影Top 50
- pdcp层的作用_LTE系统中PDCP子层功能研究