问题
问题复现步骤
前提:使用附录中建表语句先创建表
- 使用 Archery 提交一个给表 ACT_RU_TASK 创建索引的工单
ALTER TABLE
act_ru_task
ADD
INDEX `idx_parent_task_id` (`PARENT_TASK_ID_`) USING BTREE
- 提交时选择【备份sql】
引发问题
sql执行成功的那一刻,数据库在对 ACT_RU_IDENTITYLINK 表进行插入时报错:
cannot add or update a child row : a foreign key constranint fails ...
原因
Archery 在执行 sql 的时候使用到了 Inception。
说明:大概说一下 Inception 的备份机制:
- 首先会新建一张表 名为 “_ACT_RU_TASK_new” 的表
- 将原表中数据 copy 到新表中
- 在新表中执行sql
- sql 执行完成之后,ACT_RU_TASK 改名为 “ACT_RU_TASK_old”。注意:此时(ACT_RU_IDENTITYLINK 表中的外键约束已经变更为 ACT_FK_TSKASS_TASK foreign key (TASK_ID) references ACT_RU_TASK_old (ID) ,这是因为对表进行 rename 操作引起的)
- “_ACT_RU_TASK_new” 改名为 ACT_RU_TASK
- 同步数据到备份库中,删除 “_ACT_RU_TASK_old” 表
问题出现在 4,5,6,原来的表有外键约束的,通常情况下,外键表是不允许删除的,但是外键约束检测是可以被跳过的,跳过语法如下:
跳过外键检测语法:
SET FOREIGN_KEY_CHECKS=0;
drop table _ACT_RU_TASK_old;
SET FOREIGN_KEY_CHECKS=1;
在 goInception 开源项目中通过 ghost_skip_foreign_key_checks(跳过外键检查,默认为true
) 参数进行控制。问题就出现了,拥有外键约束的表被删除了,插入数据自然不能成功。
Inception 使用参数 inception_enable_foreign_key 控制
goInception 根据以下参数可以配置相应的备份信息:
backup_host "" string 备份数据库IP地址
backup_port 0 int 备份数据库端口
backup_user "" string 备份数据库用户名
backup_password "" string 备份数据库密码
解决办法
第一种: 删除外键约束,删除的后果需要自己评估
第二种: 线上的数据库一般是有主从的,暂时进行切换,等到流量低峰时期将外键约束加回去(不要再使用 archery 工单添加外键,外键语句受限制,需要 DBA 手动执行)
使用第二种办法时,注意一定要等到流量低峰,否则可能出现 死锁-长时间卡死,最后不得不 kill 掉的情况。
附录
Archery 简介
Archery 是archer的分支项目,定位于SQL审核查询平台,旨在提升DBA的工作效率,支持多数据库的SQL上线和查询,同时支持丰富的MySQL运维功能,所有功能都兼容手机端操作
在线体验
账号 密码
archer archer
开源地址
https://github.com/hhyo/Archery
api文档:https://demo.archerydms.com/api/swagger/#/v1/v1_workflow_execute_create
goInception 介绍 (goInception 是 Inception 的 go 语言版本)
goInception 是一个集审核、执行、备份及生成回滚语句于一身的MySQL运维工具, 通过对执行SQL的语法解析,返回基于自定义规则的审核结果,并提供执行和备份及生成回滚语句的功能。
开源地址
https://github.com/hanchuanchuan/goInception
文档地址
https://hanchuanchuan.github.io/goInception/zh/
表结构 此处使用 Activity 6.0 开源框架进行类比。
ACT_RU_IDENTITYLINK
sql 为 activity 6.0 源码中的原始 sql
-- ACT_RU_IDENTITYLINK
create table ACT_RU_IDENTITYLINK (
ID_ varchar(64),
REV_ integer,
GROUP_ID_ varchar(255),
TYPE_ varchar(255),
USER_ID_ varchar(255),
TASK_ID_ varchar(64),
PROC_INST_ID_ varchar(64),
PROC_DEF_ID_ varchar(64),
primary key (ID_)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin;
-- 索引
create index ACT_IDX_IDENT_LNK_USER on ACT_RU_IDENTITYLINK(USER_ID_);
create index ACT_IDX_IDENT_LNK_GROUP on ACT_RU_IDENTITYLINK(GROUP_ID_);
create index ACT_IDX_ATHRZ_PROCEDEF on ACT_RU_IDENTITYLINK(PROC_DEF_ID_);
-- 外键约束
alter table ACT_RU_IDENTITYLINK
add constraint ACT_FK_TSKASS_TASK
foreign key (TASK_ID_)
references ACT_RU_TASK (ID_);
alter table ACT_RU_IDENTITYLINK
add constraint ACT_FK_ATHRZ_PROCEDEF
foreign key (PROC_DEF_ID_)
references ACT_RE_PROCDEF(ID_);
alter table ACT_RU_IDENTITYLINK
add constraint ACT_FK_IDL_PROCINST
foreign key (PROC_INST_ID_)
references ACT_RU_EXECUTION (ID_);
ACT_RU_TASK
create table ACT_RU_TASK (
ID_ varchar(64),
REV_ integer,
EXECUTION_ID_ varchar(64),
PROC_INST_ID_ varchar(64),
PROC_DEF_ID_ varchar(64),
NAME_ varchar(255),
PARENT_TASK_ID_ varchar(64),
DESCRIPTION_ varchar(4000),
TASK_DEF_KEY_ varchar(255),
OWNER_ varchar(255),
ASSIGNEE_ varchar(255),
DELEGATION_ varchar(64),
PRIORITY_ integer,
CREATE_TIME_ timestamp(3) NULL,
DUE_DATE_ datetime(3),
CATEGORY_ varchar(255),
SUSPENSION_STATE_ integer,
TENANT_ID_ varchar(255) default '',
FORM_KEY_ varchar(255),
CLAIM_TIME_ datetime(3),
primary key (ID_)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin;
create index ACT_IDX_TASK_CREATE on ACT_RU_TASK(CREATE_TIME_);
alter table ACT_RU_TASK
add constraint ACT_FK_TASK_EXE
foreign key (EXECUTION_ID_)
references ACT_RU_EXECUTION (ID_);
alter table ACT_RU_TASK
add constraint ACT_FK_TASK_PROCINST
foreign key (PROC_INST_ID_)
references ACT_RU_EXECUTION (ID_);
alter table ACT_RU_TASK
add constraint ACT_FK_TASK_PROCDEF
foreign key (PROC_DEF_ID_)
references ACT_RE_PROCDEF (ID_);