查看: 3787|回复: 6

[转载] 外键字段未建索引引发的死锁

[复制链接]
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
跳转到指定楼层
1#
发表于 2011-6-12 06:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
外键字段未建索引引发的死锁



现象:一个很简单的程序在压力测试过程中发现死锁,查看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



首先注意到的是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:为什么删除子表记录的时候要加表级的共享锁呢?还有这个加锁好像只是一瞬间的,期待深入!!!



发表于: 2009-04-09,修改于: 2009-04-09 15:31,已浏览1802次,有评论0条 推荐 投诉
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
2#
 楼主| 发表于 2011-6-12 06:24 | 只看该作者
btw,mysql貌似外键自动加索引

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
3#
发表于 2011-6-12 06:27 | 只看该作者
结论是错的:
而且如果外键设置为级联删除,则不加索引的外键会使得对子表的记录删除走全表扫描。因此,对外键的使用还是要慎重!

应该是在删除父表的时候。
这个问题说得很多了。

使用道具 举报

回复
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
4#
发表于 2011-6-12 11:14 | 只看该作者
而且11g已经把死锁这个去掉了

使用道具 举报

回复
论坛徽章:
58
生肖徽章2007版:马
日期:2009-11-06 23:12:33授权会员
日期:2013-01-10 14:38:592013年新春福章
日期:2013-02-25 14:51:24马自达
日期:2013-08-07 10:54:45红旗
日期:2013-08-09 13:48:48劳斯莱斯
日期:2013-09-12 15:56:37萤石
日期:2013-10-31 08:44:19优秀写手
日期:2013-12-18 09:29:13Jeep
日期:2014-01-14 10:53:432014年新春福章
日期:2014-02-18 16:43:09
5#
发表于 2011-6-12 21:50 | 只看该作者
学习……

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
6#
发表于 2011-6-12 23:08 | 只看该作者
原帖由 dingjun123 于 2011-6-12 11:14 发表
而且11g已经把死锁这个去掉了

还是可能发生的,只是可能性降低了,因为DML结束,子表上的锁就解开而不是等到提交才解开。

使用道具 举报

回复
论坛徽章:
10
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44奥运会纪念徽章:马术
日期:2012-08-28 15:37:12奥运会纪念徽章:曲棍球
日期:2012-08-16 11:06:362012新春纪念徽章
日期:2012-02-07 09:59:352012新春纪念徽章
日期:2012-01-04 11:51:22ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26复活蛋
日期:2011-08-16 14:50:51鲜花蛋
日期:2011-06-13 13:26:292011新春纪念徽章
日期:2011-02-18 11:43:362013年新春福章
日期:2013-02-25 14:51:24
7#
发表于 2011-6-13 13:27 | 只看该作者
恩,不错,学习了。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表