本文地址:https://www.cnblogs.com/ajiangg/p/9850902.html
约半年前上线了去哪儿的开源审核工具Inception(最近发现已经闭源了.....)以及基于Inception的SQL审核平台Yearning。
一直都用得很爽...直到昨天踩坑。

昨天晚上某个表A新加了一个字段,今早收到业务告警。最后从日志中发现类似如下报错(B表的外键指向了不存在的表_A_old):
Cannot add or update a child row: a foreign key constraint fails (db.B, CONSTRAINT B_ibfk_2 FOREIGN KEY (A_id) REFERENCES _A_old (id))
至于为啥会有外键...这属于历史遗留问题。

第一反应,昨天加字段的时候Inception调用pt-osc出问题了,导致外键没有链接到新表上去。
既然pt-osc会有问题,那就老老实实直接删除外键,重加吧
alter table B drop foreign key B_ibfk_2,add constraint new_key FOREIGN KEY (A_id) REFERENCES A(id)
悲剧的是B表实在是太大,线上跑了一个小时也无果,于是Kill回滚。

回过头来研究为毛B表会指向利用pt-osc进行字段增加时的旧表_A_old呢?
先看看pt-osc关于外键的参数--alter-foreign-keys-method:
(1)auto
自动决定采用哪个方法,如果可以就采用rebuild_constraints,如果不可以就采用drop_swap
(2)rebuild_constraints
该方法采用alter table来drop并re-add链接新表的外键。除非相关的子表太大使得alter过程花费时间过长,一般都采用该方法。这里的花费时间是通过比较子表中的行数和该工具将原始表数据拷贝到新表中的拷贝速率来评估的,如果评估后发现子表中数据能够在少于--chunk-time的时间内alter完成,就会采用该方法。另外,因为在MySQL中alter table比外部拷贝数据的速率快很多,所以拷贝速率是按照--chunk-size-limit来决定的
因为MySQL的限制,外键在改表前后的名字会不一样,改表后新表中的外键名前会加一个下划线,同样,会自动的更改外键相应的索引名字
(3)drop_swap
该方法禁止外键检查(FOREIGN_KEY_CHECKS=0),然后在rename新表之前就将原始表drop掉,这个方法更快而且不会被阻塞,但是风险比较大,风险有二:
在drop掉原始表和rename新表之间有一个时间差,在这段时间里这个表是不存在的,这会导致查询报错
如果rename新表时发生了错误,那问题就大了,因为原始表已经被drop掉了,只能呵呵了
(4)none
这个方法类似没有"swap"的drop_swap,原始表中的所有外键都会被指定到一个不存在的表上
因为原始表(database.tablename)会被rename为database.tablename_old然后drop掉。这种处理外键的方法可以让DBA在需要时取消该工具的这种内置功能

以下是我关于这些参数的测试结果(参数auto略过了):
1.有子表的表A使用最安全的--alter-foreign-keys-method=rebuild_constraints来进行线上更新时,
在copy完父表之后,子表进行更改的方式是alter table B drop foreign key old_key,add constraint new_key FOREIGN KEY (A_id) REFERENCES A(id)。如果子表B比较大,或者A表有好几个子表,那么我还有使用pt-osc的必要么?(对线上的影响可能远远大于直接alter table A带来的影响)

2.有子表的表A使用--alter-foreign-keys-method=none来进行线上更新时,
在copy完父表之后,数据库是直接执行set FOREIGN_KEY_CHECKS=0,然后drop旧表_A_old,然后rename新表_A_new为A。然后就收工了。
所以子表B的外键指向的仍然是pt-osc运行过程中的那张原始父表_A_old
很显然,Inception针对pt-osc的默认配置就是使用--alter-foreign-keys-method=none。

3.有子表的表A使用--alter-foreign-keys-method=drop_swap来进行线上更新时,
在copy完父表之后,数据库是直接执行set FOREIGN_KEY_CHECKS=0,然后drop旧表_A_old,然后rename新表_A_new为_A_old,最后再rename为A。
这样弄完之后父子表的关系仍然存在。(在rename_A_new为_A_old之后,drop旧表_A_old产生的错误指向就被带回来了)
--------------------------------------------------------------------------------------解决方法-----------------------------------------------------------------------------------------------
既然rename表之后,子表的外键关系能跟着变,那么最后线上问题的修正方法也就有了:
现在子表B的外键指向是一个不存在的表_A_old,那么我把现在的A表rename成_A_old,外键关系联系上了之后再重新rename回A表,不就好了么:
alter table A rename _A_old;
alter table _A_old rename A;
经测试没问题,秒恢复正常,然后线上执行OK。

最后回过头来检查Inception关于pt-osc对外键的配置发现:
inception_osc_alter_foreign_keys_method的默认配置是none(即它调用pt-osc的默认参数为--alter-foreign-keys-method=none),所以出现了外键指向不存在的表。
在这里我将配置改成了drop_swap

--------------------------------------------------------------------------------------华丽丽的分割线-----------------------------------------------------------------------------------------------
最后的反省:
数据库有变更的时候,变更完成后需要对相关的业务进行检查。这次虽然我们业务告警系统也在变更之后立即告警了,但却当成“狼来了”给略过了,此处需向老板好好反省......
关于外键,一直都是抵制的。对于新表,新需求一直都禁止使用外键。但旧的系统,很难推动去改掉它。
以前对于外键的一些细节,总是想着反正不会用到,所以遇到这样的细节直接就跳过了。
现在看来,虽然可能一般不会碰到,但这些细节还是需要好好的去理解掌握。
本文地址:https://www.cnblogs.com/ajiangg/p/9850902.html

关于Inception默认配置的一个坑的更多相关文章

  1. 关于win7+VS2017环境下的opencv-contirb配置的一个坑

    问题出现背景: 由于课题需要用到SURF detector, 我依照网上的一下教程,把opencv-contrib的配置了一遍.但是,当我写了一个小demo来测试模块是否能正常使用的时候,程序能正常编 ...

  2. python的默认参数的一个坑

    前言 pass 正文 在 https://docs.python.org/3/tutorial/controlflow.html#default-argument-values 中,有这样一段话 Im ...

  3. Druid连接池默认配置和坑

    一.公司默认配置 ds_0: !!com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: ...

  4. 关于fastjson的一个坑:输出json时,bean对象属性首字母默认被小写

    fastjson 是一个性能很好的 Java 语言实现的 JSON 解析器和生成器,来自阿里巴巴. 主要特点: 快速FAST: 比其它任何基于Java的解析器和生成器更快,包括jackson 强大:支 ...

  5. dubbox注解的一个坑

    我和我同事Daniel排查的一个问题,原文是我同事Daniel写的,我做了些修改了补充. 我们dubbox的provider端有很多service开发时没有考虑到幂等问题,于是只能暂时关掉dubbo的 ...

  6. CentOS 7下升级MySQL5.7.23的一个坑

    发现CentOS 7下升级MySQL5.7.23的一个坑,以前面升级到MySQL 5.7.23的一个集群为例 在我们环境下打开文件描述符个数的参数open_files_limit在MySQL 5.6. ...

  7. 关于props default 数组/对象的默认值应当由一个工厂函数返回

    export default {props: { xAxisData: {   type: Array,   default: [] }, },这是我的代码 报错是Invalid default va ...

  8. SpringBoot整合log4j2进行日志配置及防坑指南

    写在前面 最近项目经理要求将原先项目中的日志配置logBack,修改为log4j2,据说是log4j2性能更优于logback,具体快多少,网上有说快10多倍,看来还是很快的,于是新的一波挑战又开始了 ...

  9. 记前端状态管理库Akita中的一个坑

    记状态管理库Akita中的一个坑 Akita是什么 Akita是一种基于RxJS的状态管理模式,它采用Flux中的多个数据存储和Redux中的不可变更新的思想,以及流数据的概念,来创建可观察的数据存储 ...

随机推荐

  1. 西安活动 | 9月15号 "拥抱开源, 又见.NET" 线下交流活动

    随着.NET Core的发布和开源,.NET又重新回到了人们的视野.除了开源.跨平台.高性能以及优秀的语言特性,越来越多的第三方开源库也出现在了github上——包括ML.NET机器学习.Xamari ...

  2. go os/exec执行外部程序

    Go提供的os/exec包可以执行外部程序,比如调用系统命令等. 最简单的代码,调用pwd命令显示程序当前所在目录: package main import ( "fmt" &qu ...

  3. HTML语法介绍

    一 基本标签(块级标签和内联标签) <hn>: n的取值范围是1~6; 从大到小. 用来表示标题. <p>: 段落标签. 包裹的内容被换行.并且也上下内容之间有一行空白. &l ...

  4. 不规范的json文档 转化成 java 对象的处理

    最近练习爬取数据,遇到了json文档中属性名称没有用双引号的情况,内容如下: 标准的json文档,属性名称都是带双引号的 最后写了个方法,替换属性名字 为 两头追加双引号的属性名字, 特别要注意,防止 ...

  5. Java网络编程的基本网络概念

    前言 自己网络这方面的知识很是薄弱,每次面试被问到这部分都会卡壳,所以很尴尬,然后最近也是有些时间了,就赶紧把自己的不足补充一下.虽然最近也在看设计模式,但是总看设计模式也容易烦,所以就并行学习,看看 ...

  6. 高可用集群之keepalived+lvs实战-技术流ken

    keepalived简介 lvs在我之前的博客<高负载集群实战之lvs负载均衡-技术流ken>中已经进行了详细的介绍和应用,在这里就不再赘述.这篇博文将把lvs与keepalived相结合 ...

  7. 南大算法设计与分析课程OJ答案代码(5)--割点与桥和任务调度问题

    问题 A: 割点与桥 时间限制: 1 Sec  内存限制: 5 MB提交: 475  解决: 34提交 状态 算法问答 题目描述 给出一个无向连通图,找到所有的割点和桥 输入 第一行:点的个数,如果点 ...

  8. javascript小实例,编写一个方法,实现从n-m个数中随机选出一个整数

    别怪我是一个闷葫芦,没那么多花哨的语言,废话不多说,先说说小实例的要求: 编写一个方法,实现从n-m个数中随机选出一个整数,要求:传递的参数不足两个或者不是有效数字,返回[0-1]之间的随机数,需要解 ...

  9. IdentityServer4 中文文档 -15- (快速入门)添加 JavaScript 客户端

    IdentityServer4 中文文档 -15- (快速入门)添加 JavaScript 客户端 原文:http://docs.identityserver.io/en/release/quicks ...

  10. SQL语句害死人

    最近在弄Android的SQLite,觉得其语法是在难搞~ 在这里把一些正确规范的实例贴出来,供参考 ';