前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Insert into select语句引发的生产事故

Insert into select语句引发的生产事故

原创
作者头像
不一样的科技宅
修改于 2020-09-21 07:26:35
修改于 2020-09-21 07:26:35
2.3K0
举报

前言

  Insert into select请慎用。这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份。本想通过程序先查询查出来然后批量插入。但xxx觉得这样有点慢,需要耗费大量的网络I/O,决定采取别的方法进行实现。通过在Baidu的海洋里遨游,他发现了可以使用insert into select实现,这样就可以避免使用网络I/O,直接使用SQL依靠数据库I/O完成,这样简直不要太棒了。然后他就被开除了。

事故发生的经过。

  由于数据数据库中order_today数据量过大,当时好像有700W了并且每天在以30W的速度增加。所以上司命令xxx将order_today内的部分数据迁移到order_record中,并将order_today中的数据删除。这样来降低order_today表中的数据量。

  由于考虑到会占用数据库I/O,为了不影响业务,计划是9:00以后开始迁移,但是xxx在8:00的时候,尝试迁移了少部分数据(1000条),觉得没啥问题,就开始考虑大批量迁移。

  • 在迁移的过程中,应急群是先反应有小部分用户出现支付失败,随后反应大批用户出现支付失败的情况,以及初始化订单失败的情况,同时腾讯也开始报警。
  • 然后xxx就慌了,立即停止了迁移。

  本以为停止迁移就就可以恢复了,但是并没有。后面发生的你们可以脑补一下。

事故还原

  在本地建立一个精简版的数据库,并生成了100w的数据。模拟线上发生的情况。

建立表结构

订单表

代码语言:txt
AI代码解释
复制
CREATE TABLE `order_today` (
  `id` varchar(32) NOT NULL COMMENT '主键',
  `merchant_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '商户编号',
  `amount` decimal(15,2) NOT NULL COMMENT '订单金额',
  `pay_success_time` datetime NOT NULL COMMENT '支付成功时间',
  `order_status` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '支付状态  S:支付成功、F:订单支付失败',
  `remark` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间 -- 修改时自动更新',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_merchant_id` (`merchant_id`) USING BTREE COMMENT '商户编号'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

订单记录表

代码语言:txt
AI代码解释
复制
CREATE TABLE order_record like order_today;

今日订单表数据

模拟迁移

把8号之前的数据都迁移到order_record表中去。

代码语言:txt
AI代码解释
复制
INSERT INTO order_record SELECT
	* 
FROM
	order_today 
WHERE
	pay_success_time < '2020-03-08 00:00:00';

在navicat中运行迁移的sql,同时开另个一个窗口插入数据,模拟下单。


  从上面可以发现一开始能正常插入,但是后面突然就卡住了,并且耗费了23s才成功,然后才能继续插入。这个时候已经迁移成功了,所以能正常插入了。

出现的原因

  在默认的事务隔离级别下:insert into order_record select * from order_today 加锁规则是:order_record表锁,order_today逐步锁(扫描一个锁一个)。

分析执行过程。

  通过观察迁移sql的执行情况你会发现order_today是全表扫描,也就意味着在执行insert into select from 语句时,mysql会从上到下扫描order_today内的记录并且加锁,这样一来不就和直接锁表是一样了。

  这也就可以解释,为什么一开始只有少量用户出现支付失败,后续大量用户出现支付失败,初始化订单失败等情况,因为一开始只锁定了少部分数据,没有被锁定的数据还是可以正常被修改为正常状态。由于锁定的数据越来越多,就导致出现了大量支付失败。最后全部锁住,导致无法插入订单,而出现初始化订单失败。

解决方案

  由于查询条件会导致order_today全表扫描,什么能避免全表扫描呢,很简单嘛,给pay_success_time字段添加一个idx_pay_suc_time索引就可以了,由于走索引查询,就不会出现扫描全表的情况而锁表了,只会锁定符合条件的记录。

最终的sql
代码语言:txt
AI代码解释
复制
INSERT INTO order_record SELECT
	* 
FROM
	order_today FORCE INDEX (idx_pay_suc_time)
WHERE
	pay_success_time <= '2020-03-08 00:00:00';

执行过程

总结

  使用insert into tablA select * from tableB语句时,一定要确保tableB后面的whereorder或者其他条件,都需要有对应的索引,来避免出现tableB全部记录被锁定的情况。

参考文章

结尾

  如果觉得对你有帮助,可以多多评论,多多点赞哦,也可以到我的主页看看,说不定有你喜欢的文章,也可以随手点个关注哦,谢谢。

我是不一样的科技宅,每天进步一点点,体验不一样的生活。我们下期见!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
同事埋了个坑:Insert into select 语句把生产服务器炸了!
Insert into select请慎用。这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份。本想通过程序先查询查出来然后批量插入。但xxx觉得这样有点慢,需要耗费大量的网络I/O,决定采取别的方法进行实现。通过在Baidu的海洋里遨游,他发现了可以使用insert into select实现,这样就可以避免使用网络I/O,直接使用SQL依靠数据库I/O完成,这样简直不要太棒了。然后他就被开除了。
二哥聊运营工具
2021/12/17
3620
同事埋了个坑:Insert into select 语句把生产服务器炸了!
因用了Insert into select语句,美女同事被开除了!
Insert into select请慎用。这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份。本想通过程序先查询查出来然后批量插入。但xxx觉得这样有点慢,需要耗费大量的网络I/O,决定采取别的方法进行实现。通过在Baidu的海洋里遨游,她发现了可以使用insert into select实现,这样就可以避免使用网络I/O,直接使用SQL依靠数据库I/O完成,这样简直不要太棒了。然后她就被开除了。
java进阶架构师
2020/08/28
4760
因用了Insert into select语句,美女同事被开除了!
同事埋了个坑:Insert into select语句把生产服务器炸了
Insert into select请慎用。这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份。本想通过程序先查询查出来然后批量插入。但xxx觉得这样有点慢,需要耗费大量的网络I/O,决定采取别的方法进行实现。通过在Baidu的海洋里遨游,他发现了可以使用insert into select实现,这样就可以避免使用网络I/O,直接使用SQL依靠数据库I/O完成,这样简直不要太棒了。然后他就被开除了。
业余草
2020/04/30
3K3
同事埋了个坑:Insert into select语句把生产服务器炸了
SQL 从入门到放弃:ROW_NUMBER() OVER 和 ROLLUP
提起 SQL,(从前的)我脑子只有 SELECT、COUNT()、SUM()、JOIN、GROUP BY 等云云。对于较为复杂的数据场景,总是绞尽脑汁的用 GROUP BY 和 JOIN 来实现,却不知有类似功能的 SQL 函数。
小草学习屋
2023/11/22
5940
千万级支付对账系统是怎么设计的?
今天给大家分享一篇关于对账系统设计的文章,出自在支付行业摸爬滚打好几年的小黑哥之手。
架构之家
2022/09/01
3.6K0
千万级支付对账系统是怎么设计的?
千万级支付对账系统怎么玩(下篇)?
在 DP 核对之前,我们需要将对账系统收集的数据,从 MySQL 导入 DP Hive 表中。
andyxh
2022/05/10
9620
千万级支付对账系统怎么玩(下篇)?
项目终于用上了Spring状态机,非常优雅!
先来解释什么是“状态”( State )。现实事物是有不同状态的,例如一个自动门,就有 open 和 closed 两种状态。我们通常所说的状态机是有限状态机,也就是被描述的事物的状态的数量是有限个,例如自动门的状态就是两个 open 和 closed 。
终码一生
2023/08/22
8430
项目终于用上了Spring状态机,非常优雅!
SQL总结大厂真题-连续支付订单合并
现有一张用户支付表:t_user_pay包含字段订单ID,用户ID,商户ID,支付时间,支付金额。
数据仓库晨曦
2024/01/08
3660
SQL总结大厂真题-连续支付订单合并
分库分表—4.数据迁移系统文档一
(3)binlog消息消费记录表——etl_binlog_consume_record
东阳马生架构
2025/02/19
810
实用 SQL 语句收藏这篇就够了
语法:create index index_name on table_name (column_name)
我是一条小青蛇
2019/10/23
9470
springcloud+eureka整合阿里seata-xa模式
XA协议是X/Open组织管理的一种分布式协议规范,它采用2阶段提交来管理分布式事务,目前主流的数据库都支持xa协议。
jinjunzhu
2020/11/04
4480
springcloud+eureka整合阿里seata-xa模式
腾讯大数据面试SQL-合并连续支付订单
现有一张用户支付表:t_user_pay包含字段订单ID,用户ID,商户ID,支付时间,支付金额。如果同一用户在同一商户存在多笔订单,且中间该用户没有其他商户的支付记录,则认为是连续订单,请把连续订单进行合并,时间取最早支付时间,金额求和。
数据仓库晨曦
2024/06/17
1492
腾讯大数据面试SQL-合并连续支付订单
SQL 进阶挑战(6 - 10)
现有一张试卷作答记录表exam_record,其中包含多年来的用户作答试卷记录,结构如下表:
村雨遥
2022/06/15
3910
MySQL案例:一个有趣的慢查询问题分析
前几天,有位客户提了一个慢查询问题,需要这边帮忙分析一下;整个排查过程还是非常有趣,涉及到一些值得关注的知识点,因此在这里记录一下。
brightdeng@DBA
2021/03/01
3.3K1
MySQL案例:一个有趣的慢查询问题分析
使用ShardingSphere5.0进行数据库水平拆分过程以及所踩的坑
在学习过ShardingSphere-JDBC相关的操作之后,现在使用其对数据库进行水平拆分。
冬天里的懒猫
2021/09/26
1.5K0
故障分析 | 血的教训-由慢查询引发的备份等待导致数据库连接打满
早上一大早被拉去开早会,感觉事情不妙,得知是某中台(发券)数据库 不能正常提供访问。出现大量的下面情况 :
爱可生开源社区
2022/05/06
4040
微服务综合案例-01-需求分析
  前面我们分别给大家介绍了SpringBoot,SpringCloud的Eureka(注册中心),ribbon(负载均衡),Feign(声明式服务调用),Hystrix(服务容错)等内容,在介绍后续内容之前我们穿插通过一个案例来综合使用下前面介绍的内容。
用户4919348
2019/06/17
1.1K0
电商系统设计之订单
1. 前言2. 付款2.1 成功2.2 人祸2.4 天灾2.4 注释2.5 表结构2.5.1 交易表2.5.2 支付记录表2.5.3 订单表3. 运输4. 收货5. 退换货5.1 售后申请表5.2 售后表6. 评价6.1 评价数据表7. 致谢
芋道源码
2018/12/14
1.1K0
Dubbo 分布式架构搭建教育 PC 站 - 后端:数据库设计文档
数据库设计文档 MySQL 数据库名称:edu 数据库表: activity_course 活动课程表 course 课程表 course_comment 留言表 course_comment_favorite_record 点赞表 course_lesson 课时表 course_media 课程媒体表 course_play_history 历史播放节点表 course_section 章节表 pay_order 支付订单信息表 pay_order_record 支付订单状态日志表 promotion_
RendaZhang
2020/11/04
2K0
SpringCloud Alibaba实战(3:存储设计与基础架构设计)
在上一章中,我们已经完成了基本业务流程的梳理和服务模块的划分,接下来,开始设计数据存储。
三分恶
2021/06/11
4930
SpringCloud Alibaba实战(3:存储设计与基础架构设计)
推荐阅读
相关推荐
同事埋了个坑:Insert into select 语句把生产服务器炸了!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档