版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1417990
第一时间获取技术干货和业界资讯!
最近 996 很“热闹”,但我还是希望大家能够回归平淡,理性看待它,毕竟生活还要继续。
昨天,我们公司发生了一件“删库跑路”的事件,为此我花费了一整个通宵的时间来处理事故现场,进行数据恢复。
当我在群里讨论这件事的时候,很多程序员自黑到肯定是因为 996,其实并不是了。因为我们公司很少有加班的,基本上都是自己主动去学习,去充电。
删库容易,跑路难。事件的起因是这样的,最近有几个运营同事离职,4 月份大家都想换个环境,所以,老板就对部分运营同事的相关权限进行了回收。但是,意外发生了,老板不小心把在职的相关运营的同事的权限也回收了。而且,老板还出国去出差了。
而正在这时,运营还出了差错,发货的物流信息给搞错用户了。一些人购买的商品还没发货呢?一看订单,发现自己购买的商品被邮寄到北京了。总之就是和自己的地址不相符,这个时候投诉电话立马多了起来。
运营将问题上报,抛给了程序员。再加上老板在国外,不好分配权限,于是运营就一致决定让程序员改数据库。事情也还简单,于是就答应了,并将任务抛给了一个程序员,给他开了生产库的权限。
原本我以为事情就这么简单的结束了呢?谁知道被同事挖了一个大坑。他竟然不小心,使用 update 更新 SQL 的时候,把所有数据都更新了。年前放假前 3 天的事故再现《泪奔,同事执行 update 语句没有添加 where 条件!》,大 Boss 回来非剥了我的皮不可。
为了将风险降到最低,通知所有人,一致对外,系统正在升级,升级过程中会进行数据迁移,届时可能会造成部分数据显示不正确,敬请谅解!公关做好之后,客服也安静了。但是我却只能连夜加班,进行数据修复,苦的一逼。
造成事故的 SQL 如下:
这个 SQL 看起来没什么大问题,通过 in 查询,控制范围。但实际上,一执行竟然把所有数据都更新了。
原因出在哪里呢?
实际上,我一眼就看出来了这条 SQL 的问题。aorder_id 这个列根本就不存在。当你把下面这条语句拿出来执行,会报错。无法执行。
但当你把两条 SQL 合起来,用我上面的 in 的方式进行查询又不报错。
你在测试的时候,需要注意的是:子查询种的 aorder_id 是 order_item 中存在的,而不存在于 order 表中的。如果你的 order_item 中不存在 aorder_id 字段,那么这条语句在查询时会直接报错。
关于为什么只要子查询中取的字段是 order_item 中的字段就不报错的原因,目前网上还没有这类的文章介绍。但是我们可以通过我前面教的 EXPLAIN EXTENDED 和 SHOW WARNINGS; 来看看 MySQL 的子查询到底是如何执行的。
执行上面的语句之后,你会看到整条 SQL 被拆分成两次执行,还用到了 temporary 和 join。
接着我们在执行下面的 SQL 语句,看看结果。
贴出来,如下所示:
这表明,最终的查询变成了两表 join 查询。子查询如果在内层表里找不到字段会到外层去找这个字段。所以,你把子查询单独拿出来执行会报错,但是组合起来后并不会报错。 MySQL 会把子查询转为连接连接,为什么要这样呢?这是优化器底层实现决定的。
以上,这个坑希望大家都能够铭记!