未加索引的外键导致的死锁模拟实验以及问题

EODA@PROD1> create table pk_t (x int primary key);  --建立主角

Table created.

EODA@PROD1> insert into pk_t select rownum from dual connect by level <= 40;

40 rows created.

EODA@PROD1> commit;

Commit complete.

EODA@PROD1> create table fk_t (x int , y int);    --建立副表

Table created.

EODA@PROD1> insert into fk_t select rownum, rownum/2 from dual connect by level <= 30;

30 rows created.

EODA@PROD1> commit;

Commit complete.

EODA@PROD1> alter table fk_t add constraint fk_fkt foreign key (x) references pk_t(x); --创建外键约束

Table altered.

EODA@PROD1> select table_name, constraint_name,
  2  	    cname1 || nvl2(cname2,','||cname2,null) ||
  3  	    nvl2(cname3,','||cname3,null) || nvl2(cname4,','||cname4,null) ||
  4  	    nvl2(cname5,','||cname5,null) || nvl2(cname6,','||cname6,null) ||
  5  	    nvl2(cname7,','||cname7,null) || nvl2(cname8,','||cname8,null)
  6  		   columns
  7  	 from ( select b.table_name,
  8  		       b.constraint_name,
  9  		       max(decode( position, 1, column_name, null )) cname1,
 10  		       max(decode( position, 2, column_name, null )) cname2,
 11  		       max(decode( position, 3, column_name, null )) cname3,
 12  		       max(decode( position, 4, column_name, null )) cname4,
 13  		       max(decode( position, 5, column_name, null )) cname5,
 14  		       max(decode( position, 6, column_name, null )) cname6,
 15  		       max(decode( position, 7, column_name, null )) cname7,
 16  		       max(decode( position, 8, column_name, null )) cname8,
 17  		       count(*) col_cnt
 18  		  from (select substr(table_name,1,30) table_name,
 19  			       substr(constraint_name,1,30) constraint_name,
 20  			       substr(column_name,1,30) column_name,
 21  			       position
 22  			  from user_cons_columns ) a,
 23  		       user_constraints b
 24  		 where a.constraint_name = b.constraint_name
 25  		   and b.constraint_type = 'R'
 26  		 group by b.table_name, b.constraint_name
 27  	      ) cons
 28  	where col_cnt > ALL
 29  		( select count(*)
 30  		    from user_ind_columns i,
 31  			 user_indexes	  ui
 32  		   where i.table_name = cons.table_name
 33  		     and i.column_name in (cname1, cname2, cname3, cname4,
 34  					   cname5, cname6, cname7, cname8 )
 35  		     and i.column_position <= cons.col_cnt
 36  		     and ui.table_name = i.table_name
 37  		     and ui.index_name = i.index_name
 38  		     and ui.index_type IN ('NORMAL','NORMAL/REV')
 39  		   group by i.index_name
 40  		)
 41  /
--查找出未加索引的外键
TABLE_NAME	CONSTRAINT_NAME COLUMNS
--------------- --------------- ------------------------------
FK_T		FK_FKT		X
……

--模拟死锁
EODA@PROD1> delete from fk_t where x=1;  --第一个会话中执行删除,子表加上SX锁

1 row deleted.

EODA@PROD1> delete from pk_t where x=1;  --第一个会话中执行删除,父表加上SX锁

1 row deleted.

EODA@PROD1> delete from fk_t where x=2;  --第二个会话中执行删除

1 row deleted.

EODA@PROD1> delete from pk_t where x=2;  --第二个会话中执行删除,hang住

EODA@PROD1> delete from pk_t where x=2;  --再次在第一个会话中执行删除

EODA@PROD1> delete pk_t where x=2;
delete pk_t where x=2
       *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource   --第二个会话中立刻报错形成死锁

--再次模拟死锁
EODA@PROD1> create index idx_fk_x on fk_t(x) nologging;  --给外键增加索引

Index created.

EODA@PROD1> delete from fk_t where x=1;  --第一个会话中执行删除,子表加上SX锁

1 row deleted.

EODA@PROD1> delete from pk_t where x=1;  --第一个会话中执行删除,父表加上SX锁

1 row deleted.

EODA@PROD1> delete from fk_t where x=2;  --第二个会话中执行删除

1 row deleted.

EODA@PROD1> delete from pk_t where x=2;  --第二个会话中执行删除,均成功。

1 row deleted.


--未加索引的外键会存在的问题
1.引起全表锁。
2.当使用了on delete cascade,而且没有对子表加索引,要从父表中删除多行时,每删除一行就要扫描一次子表。
3.当你从父表查询子表,你会发现没有索引的话会使查询变慢。


--什么时候不需要对外键增加索引
1.不会从父表中删除行。
2.不会去更新父表的主键。
3.不会从父表连接到子表。


--参考来源《Oracle编程艺术深入理解数据库体系结构(第三版)》

MySQL 外键索引是用于在关系型数据库中建立表与表之间的关联关系的一种索引类型。外键索引可以用来确保数据的完整性和一致性,同时提高查询的性能。 在MySQL中,外键索引通常由两个关键字来定义:FOREIGN KEY和REFERENCES。通过FOREIGN KEY关键字,我们可以指定一个列作为外键,并指定其参照的表和列。REFERENCES关键字用于指定被参照的表和列。 例如,假设我们有两个表:订单表和客户表。订单表中有一个列customer_id用于存储客户ID,我们可以将其定义为外键,并指定参照的是客户表的ID列。 ```sql CREATE TABLE customer ( id INT PRIMARY KEY, name VARCHAR(100) ); CREATE TABLE order ( id INT PRIMARY KEY, customer_id INT, order_date DATE, FOREIGN KEY (customer_id) REFERENCES customer(id) ); ``` 上述示例中,order表的customer_id列被定义为外键,并参照了customer表的id列。这样,当我们在order表中插入数据时,系统会自动检查customer_id的值是否存在于customer表的id列中,以确保数据的完整性。 外键索引可以提高查询的性能,特别是在涉及到跨表查询时。它可以帮助数据库优化查询计划,并加速数据检索过程。 需要注意的是,使用外键索引的同时也需要考虑数据库的性能和维护成本。过多的外键关系可能会影响插入、更新和删除操作的性能。因此,在设计数据库时,需要权衡数据完整性和性能之间的平衡。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值