点击上方 web项目开发,选择 设为星标

优质文章,及时送达

--

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全部记录被锁定的情况。

# 参考

  • https://blog.csdn.net/asdfsadfasdfsa/article/details/83030011

作者:不一样的科技宅来源:juejin.im/post/5e670f0151882549274a65ef

--完--

推荐案例

  • Springboot+Vue前后端分离实现Excle文件导入并在前端页面回显功能

  • Springboot+Vue实现从数据库中获取数据生成树状图在前端页面展示功能

  • Springboot+Vue实现从数据库中获取数据生成饼状图并在前端页面展示功能

  • Springboot+Vue实现批量文件上传(pdf、word、excel)并支持在线预览功能

  • Springboot+Vue实现滑动验证成功后登录功能

  • Springboot+Vue实现从数据库中获取数据生成折线图并在前端页面展示功能

  • Springboot+Vue实现网页内容生成图片功能

  • Springboot+Vue实现信息批量修改功能

  • 查看全部案例...

温暖提示

为了方便大家更好的学习,本公众号经常分享一些完整的单个功能案例代码给大家去练习,如果本公众号没有你要学习的功能案例,你可以联系小编(微信:xxf960513)提供你的小需求给我,我安排我们这边的开发团队免费帮你完成你的案例。注意:只能提单个功能的需求不能要求功能太多,比如要求用什么技术,有几个页面,页面要求怎么样?

请长按识别二维码

想学习更多的java功能案例请关注

Java项目开发

如果你觉得这个案例以及我们的分享思路不错,对你有帮助,请分享给身边更多需要学习的朋友。别忘了《留言+点在看》给作者一个鼓励哦!

只能获取fixed语句初始值_因用了Insert into select语句,美女同事被开除了!相关推荐

  1. jQuery html()方法获取tr/td/th标签的HTML的代码获取不到,只能获取到里面的值

    jQuery html()方法获取tr/td/th标签的HTML的代码获取不到,只能获取到里面的值 下载有这样一段dom <div id="div-a" ><tr ...

  2. sql初学者指南_初学者SQL示例:SQL SELECT语句的用法

    sql初学者指南 SQLSELECT statements are used to retrieve data from the database and also, they populate th ...

  3. INSERT INTO SELECT语句概述和示例

    This article covers the SQL INSERT INTO SELECT statement along with its syntax, examples and use cas ...

  4. insert into select语句锁表故障

    深入研究insert into select语句锁表故障(上) 故障描述 前几天,一个mysql数据库运维同事,在生产上用insert into select * from语句,在生产上备份了一张表, ...

  5. SQL Server 中 SELECT INTO 和 INSERT INTO SELECT语句的区别

    SQL Server 中 SELECT INTO 和 INSERT INTO SELECT语句的区别 我们在写存储过程的时候经常会遇到需要将查询到的数据存到一张表里面的情况,如将一个table1的数据 ...

  6. 了解SQL INSERT INTO SELECT语句

    In this article, we will be focusing on Working of SQL INSERT INTO SELECT statement altogether. 在本文中 ...

  7. SQL的INSERT INTO和INSERT INTO SELECT语句

    INSERT INTO语句用来给一个table插入信息的records. 语法: 第一种,指定列名和插入的值 INSERT INTO table_name (column1, column2, col ...

  8. SQL INSERT INTO SELECT 语句

    SQL INSERT INTO SELECT 语句 通过SQL,可以从一个表复制信息到另一个表. INSERT INTO SELECT 语句从一个表复制数据,然后把数据插入到一个已存在的表中.目标表中 ...

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

    " Insert into select 请慎用,同事因为使用了 Insert into select 语句引发了重大生产事故,最后被开除. 作者:不一样的科技宅 https://jueji ...

最新文章

  1. C#——Circle(圆)类
  2. javascript 校验 非空_JavaScript_form表单非空验证;
  3. 特斯拉员工入职3天就“偷”代码,悄悄备份6300多Python脚本
  4. 使用powershell批量导入AD用户
  5. class AbstractAPI(metaclass=AbstractAPIMeta):SyntaxError: invalid syntax
  6. Ajax — 大事件项目(第二天)
  7. Java日期及时间库插件 -- Joda Time.
  8. Java Servlet总结
  9. xtu DP Training C.炮兵阵地
  10. 实现消息存档—微信聊天记录组件
  11. 费马小定理 (证明)
  12. GAMES101课程学习笔记—Lec 02:Linear Algebra 线性代数回顾
  13. matlab 画qq图,科学网—[转载]R语言绘制QQ图 - 刘朋的博文
  14. Office Word中由于自定义了新的样式名称,而导致题注显示:错误!文档中没有指定的样式文字
  15. java并发集合框架学习记录
  16. 结对编程java实现四则运算(张铭 吴昊)
  17. MAX17043锂电池电量测量芯片C51驱动
  18. 建站之星网站迁移攻略
  19. npm run build appeared(出现) Cannot find module ‘webpack/lib/ModuleFilenameHelpers‘
  20. 本地计算机无法启动theme服务,无法启动themes服务_Themes开机自动启动

热门文章

  1. VMware为全球数字化基础架构提供原生安全
  2. 我竟然混进了 Python 高级圈子!
  3. 国内RISC-V产学研基地成立,Intel、Arm、RISC-V将三分天下?
  4. 你需要掌握的事件分发高阶知识
  5. 开发怼产品,天经地义?大惊小怪?
  6. 挑战程序设计竞赛_我系首次参加第六届中国大学生程序设计竞赛网络预选赛
  7. java jdbc 连接mysql数据库,Java 通过JDBC连接Mysql数据库
  8. python更新数据库表的时间字段_python更新数据库中某个字段的数据(方法详解)
  9. 分布式ELK日志采集系统
  10. 企业实战_15_MySql主从复制到MyCat总结