现象:删除数据较慢,期间无阻塞、触发器等其他依赖影响,排查为外键引起
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'; -- 表名
删除外键测试,效率正常
--删除外键
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
文章
阅读量
获赞
