同事埋了个坑:Insert into select 语句把生产服务器炸了!

【WSL】window11 安装WSL2配置conda环境及mlatom环境搭建 写这篇文章之前自己安装过两次环境,可能每次都会产生碰到同样的问题,为了搭建适合自己的虚拟环境保证每一步的正确性,按顺序记录一下。 阅读详情

点击上方“芋道源码”,选择“设为星标”

做积极的人,而不是积极废人!

源码精品专栏

 
  • 前言

  • 事故发生的经过。

  • 事故还原

    • 建立表结构

    • 模拟迁移

  • 出现的原因

  • 解决方案

  • 总结

  • 参考文章

  • 结尾


前言

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的数据。模拟线上发生的情况。

建立表结构

订单表

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;

订单记录表

CREATE TABLE order_record like order_today;

今日订单表数据

模拟迁移

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

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

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后面的where,order或者其他条件,都需要有对应的索引,来避免出现tableB全部记录被锁定的情况。

参考文章

  • insert into … select 由于SELECT表引起的死锁情况分析

结尾

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



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

BMS开发避坑指南:如何用ADBMS6815实现0.03%精度的电池采样? 本文深入解析了如何利用ADBMS6815等高精度AFE芯片,在车规级BMS开发中实现0.03%级别的电池电压采样精度。文章从芯片选型、硬件设计、软件配置、算法优化到系统验证,提供了一套完整的实战指南,帮助工程师系统性地提升BMS测量精度,从而保障电池安全、延长寿命并增强产品竞争力。 阅读详情

相关推荐

立创开源4G+GPS定位系统:基于微信小程序的低成本低功耗追踪方案

本文介绍了一个基于立创开源平台的超小型4G+GPS定位系统方案。该方案采用28mm*28mm主板,集成4G Cat.1通信与GPS定位,通过微信小程序“点灯专家”实现远程追踪管理,具备低成本、低功耗、易于部署的特点,适用于电动车、宠物、资产追踪等多种场景。

weixin_28895791的博客 394

血一般的教训,请慎用Insert Into Select

https://www.bilibili.com/read/cv10122441

兴趣是最好的老师 524

FPGA调试利器:VIO与ILA在Vivado中的实战应用指南

本文详细介绍了Vivado中FPGA调试工具VIO与ILA的实战应用技巧。VIO作为虚拟输入/输出工具,可实时调整参数;ILA作为集成逻辑分析仪,能高效捕获内部信号。文章通过具体案例展示了如何配置ILA采样深度、触发条件,以及VIO的动态参数调整功能,帮助开发者提升上板调试效率,解决常见通信失败、数据不同步等问题。

weixin_42553471的博客 424

Insert into select为什么不可随意用

Insert into select为什么不可随意用 Insert into select请慎用。经常有人将A表的数据迁移到表B中去做一个备份,想通过程序先查询查出来然后批量插入。但考虑到需要耗费大量的网络I/O,所以使用insert into select实现,这样就可以避免使用网络I/O,直接使用SQL依靠数据库I/O完成。 但是… 例如我们要把order_today表的数据备份到order_record表。 在默认的事务隔离级别下:insert into order_record select * f

小八成长记 957

硬方案——几种实用的恒流源电路设计方案,敬请收藏(运放、三极管在手,让你玩出多种花样)

0 引言 我们在信号测量、供电等应用场景时常会涉及到使用恒流源,以前觉得恒流源挺神奇的,研究了下实现方案,其实也没有多么高深(这里讨论的仅限于用在信号测量中的小电流恒流源设计),这里给出几个实用的恒流源电路设计方案。 1 恒流源电路设计 (1)使用三极管搭建的恒流源 (2)使用运放搭建的恒流源 (3)使用恒流二极管搭建的恒流源 pt100恒流源测温电路图_电子技术_电工之家 ...

数字世界 万物互联 9524

增量学习入门:概念、代码示例与应用场景

在当今快速变化的数据环境中,传统的机器学习模型往往需要重新训练以适应新的数据。然而,这种方法不仅耗时耗力,还可能导致模型性能的不稳定。增量学习(Incremental Learning)作为一种新兴的学习范式,能够在新数据到来时动态更新模型,而无需重新训练整个模型。本文将详细介绍增量学习的基本概念、代码示例、应用场景以及需要注意的事项。增量学习作为一种高效的机器学习方法,能够在新数据到来时动态更新模型,具有广泛的应用前景。通过本文的介绍,相信你对增量学习有了初步的了解。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 1152

血一般的教训,请慎用insert into select

“ 血一般的教训,请慎用 insert into select。同事应用之后,导致公司损失了近 10w 元,最终被公司开除。 事情的起因 公司的交易量比较大,使用的数据库是 MySQL,每天的增量差不多在百万左右,公司并没有分库分表,所以想维持这个表的性能只能考虑做数据迁移。 同事李某接到了这个任务,于是他想出了这两个方案: 先通过程序查询出来,然后插入历史表,再删除原表。 使用 insert into select 让数据库 IO 来完成所有操作。 第一个方案使用的时候发现..

qq_24692021的博客 6182

【APM】在Kubernetes中搭建OpenTelemetry+Loki+Tempo+Grafana链路追踪(实战一,Loki日志中查看链路追踪数据)

这对于那些不能直接控制 JVM 启动参数的应用特别有用,比如通过 JNI (Java Native Interface) 调用 JVM 的应用、脚本中嵌入的 JVM 应用,或者一些服务管理工具自动启动的服务。这为用户提供了一个灵活的架构,可以根据需要选择最适合自己的追踪解决方案,或者根据环境(如开发、测试、生产)的不同配置不同的后端。: OpenTelemetry SDK 提供了丰富的特性,如自动追踪上下文传播、手动追踪跨度的创建与关联、标签和事件的添加等,使得追踪数据更加丰富和有用。

CN_Eden 3241

Insert into select语句把生产服务器炸了

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

weixin_39388918的博客 2758

从零构建爬虫抓取故宫数字文物库:Python最新实战技术详解

熟悉了动态内容加载的网页结构解析技巧。掌握了 Playwright + BeautifulSoup 的组合用法。实现了从网页→JSON→详情→图像的完整数据闭环。掌握了结构化保存与可视化分析能力。

2201_76125261的博客 1307

【GlobalMapper精品教程】001:GlobalMapper23+24+25 Pro-x64中文汉化版安装教程(附软件包下载)

Global Mapper 23+V24+V25中文汉化版安装教程及免费下载地址,是一款非常专业的地图绘制软件,功能非常的丰富,内置距离和面积计算,包括光栅混合、对比度调节、海拔高度查询、视线计算以及一些高级功能,通过地表数据观察分水岭、对3Dpoint数据转换为三角多边形和网格化等设置。本文讲解GlobalMapper23.1 Pro-x64安装过程。

智慧空间实验室 3万+

mongo 跨库跨表写数据(类似mysql的 insert into ... select)

db.getSiblingDB('source_db_name').getCollection('source_table_name').find().forEach(function(x){db.getSiblingDB('dest_db_name').getCollection('dest_table_name').insert(x);})

u011840205的博客 667

abapGit 安装与初始化完整指南:从 on-premise 到 SAP BTP ABAP environment 的一条龙实践

本文为ABAP开发者提供abapGit从安装到团队协作的完整指南。内容涵盖社区版ZABAPGIT的on-premise安装、Eclipse ADT插件配置、BTP环境使用及常见网络问题处理。重点包括:获取最新构建的安装步骤、EN语言环境的重要性、ADT插件安装方法、以及如何实现on-premise与BTP间的代码迁移。文中特别强调企业环境下代理设置、证书配置等注意事项,并提供实际操作案例,如将RAP业务对象迁移到BTP环境。文末附有可复用的实施清单,帮助开发者快速落地abapGit。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 417

同事埋了个坑:Insert into select语句把生产服务器炸了

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

ITjianshuzhai的博客 1053

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

同事给我埋了个坑:Insert into select语句把生产服务器炸了

作者:不一样的科技宅juejin.im/post/5e670f0151882549274a65ef前言Insert into select请慎用。这天xxx接到一个需求,需要将表A的数...

emprere的博客 954

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

因用了Insert into select语句,同事被开除了!

“ Insert into select 请慎用,同事因为使用了 Insert into select 语句引发了重大生产事故,最后被开除。图片来自 Pexels某天 xxx 接到一个需...

大数据星球-浪尖 5214

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

上一篇: 芋道 Spring Boot API 接口文档 Swagger 入门
下一篇: Apollo 源码解析 —— Portal 创建 Cluster
公众号-芋道源码
博客等级 码龄10年 1631粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值