注册
外键引起的数据修改或删除耗时异常排查分析
技术分享/ 文章详情 /

外键引起的数据修改或删除耗时异常排查分析

Dora 2026/03/27 144 3 0

结论

现象:删除数据较慢,期间无阻塞、触发器等其他依赖影响,排查为外键引起

delete、update时外键引用关系需要检查父子表数据,由于子表效率较差,导致父表delete、update效率异常。
父表删除数据,需检查历遍子表数据是否符合外键规则,该效率为子表的查询效率。
若外键信息越多,会存在更多效验、耗时,需要子表对应列手动添加索引,或建立外键的时候添加WITH INDEX同步创建索引,规避该现象

测试步骤

--构造数据
CREATE  TABLE T_01( ID  INT,DB_TYPE VARCHAR(20));
CREATE TABLE "T_02"("ID" INT,"DB_TYPE" VARCHAR(20) NOT NULL,PRIMARY KEY("DB_TYPE"));
INSERT INTO T_02 SELECT  LEVEL,LEVEL FROM DUAL  CONNECT BY LEVEL  <=100 ;
INSERT INTO T_01 SELECT  LEVEL,1 FROM DUAL  CONNECT BY LEVEL  <10000000 ;
COMMIT;
--执行正常1ms
DELETE T_02 WHERE DB_TYPE ='99';

查看计划及ET信息,无异常

--计划
1   #DELETE : [0, 0, 0]; table(T_02), type(select), mpp_opt(0), hp_opt(0)
2     #PRJT2: [1, 1, 60]; exp_num(2), is_atom(FALSE) 
3       #CSEK2: [1, 1, 60]; scan_type(UNIQUE), INDEX33555541(T_02), scan_range['99','99']

--et信息
PRJT2	1	2.33%	4	2	2	0	0	0	0	null	null	0	null
DELETE2	7	16.28%	3	1	2	0	0	0	0	null	null	0	null
DLCK	8	18.60%	2	0	2	0	0	0	0	null	null	0	null
CSEK2	27	62.79%	1	3	1	0	0	0	0	null	null	0	null

创建外键测试

--创建外键
ALTER TABLE  T_01 ADD  CONSTRAINT "T_01_FKEY" FOREIGN KEY("DB_TYPE") REFERENCES  T_02("DB_TYPE");
--删除效率异常 10s
DELETE T_02 WHERE DB_TYPE ='80';

查看计划与ET信息,02只有100条数据,但需要全表扫描10000000次,排查表相关信息,无阻塞、触发器等限制,数据操作不应该耗时这么长,并且et看操作符与预期不符,差异较大,去除其他可能性后,检查外键信息

--计划
1   #DELETE : [0, 0, 0]; table(T_02), type(select), mpp_opt(0), hp_opt(0)
2     #PRJT2: [1, 1, 60]; exp_num(2), is_atom(FALSE) 
3       #CSEK2: [1, 1, 60]; scan_type(UNIQUE), INDEX33555541(T_02), scan_range['99','99']
--et信息
PRJT2	2	0%	6	2	4	0	0	0	0	null	null	0	null
NAST2	2	0%	6	0	2	0	0	0	0	null	null	0	null
DLCK	9	0%	5	0	2	0	0	0	0	null	null	0	null
CSEK2	16	0%	4	3	2	0	0	0	0	null	null	0	null
DELETE2	47	0%	3	1	4	0	0	0	0	null	null	0	null
SLCT2	3532000	36.32%	2	0	10000001	0	0	0	0	null	null	0	null
CSCN2	6192268	63.68%	1	0	10000000	0	0	0	0	null	null	0	null

以下sql可看出依赖T_02的外键,当T_02数据变更时,依赖表T_01的数据都需要检查是否符合外键规则,所以外键信息越多,会存在更多效验、耗时

SELECT
    A.OWNER AS 外键拥有者,
    A.TABLE_NAME AS 子表名,
    A.CONSTRAINT_NAME AS 外键名称,
    B.TABLE_NAME AS 父表名
FROM
    DBA_CONSTRAINTS A
JOIN
    DBA_CONSTRAINTS B
ON
    A.R_CONSTRAINT_NAME = B.CONSTRAINT_NAME
WHERE
    B.TABLE_NAME = 'T_02';  -- 表名

image.png
删除外键测试,效率正常

--删除外键
ALTER TABLE  T_01 DROP CONSTRAINT "T_01_FKEY";
--执行 1ms
DELETE T_02 WHERE DB_TYPE ='70';

T_01表对应列手动建立索引,或创建外键的加上WITH INDEX

--外键加上 with index 后效率正常
ALTER TABLE  T_01 ADD  CONSTRAINT "T_01_FKEY" FOREIGN KEY("DB_TYPE") REFERENCES  T_02("DB_TYPE") WITH INDEX ;
--执行 1ms
DELETE T_02 WHERE DB_TYPE ='91';

查看计划及ET信息,ET的10000000次全表扫描没了,多了个SSEK2索引定位

--执行计划 无变化
1   #DELETE : [0, 0, 0]; table(T_02), type(select), mpp_opt(0), hp_opt(0)
2     #PRJT2: [1, 1, 60]; exp_num(2), is_atom(FALSE) 
3       #CSEK2: [1, 1, 60]; scan_type(UNIQUE), INDEX33555541(T_02), scan_range['95','95']

--ET信息
NAST2	1	0.85%	5	0	2	0	0	0	0	null	null	0	null
MVCK2	1	0.85%	5	0	2	0	0	0	0	null	null	0	null
PRJT2	1	0.85%	5	2	4	0	0	0	0	null	null	0	null
DLCK	12	10.17%	4	0	2	0	0	0	0	null	null	0	null
SSEK2	14	11.86%	3	0	1	0	0	0	0	null	null	0	null
CSEK2	39	33.05%	2	3	2	0	0	0	0	null	null	0	null
DELETE2	50	42.37%	1	1	4	0	0	0	0	null	null	0	null
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服