点击上方“方志朋”,选择“设为星标”

回复”666“获取新整理的面试文章

# 前言

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*
FROMorder_today
WHEREpay_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*
FROMorder_today FORCE INDEX (idx_pay_suc_time)
WHEREpay_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


热门内容:我们已经不用AOP做操作日志了!Spring Boot+JWT+Shiro+MyBatisPlus 实现 RESTful 快速开发后端脚手架
MyBatis动态SQL(认真看看, 以后写SQL就爽多了)
选型必看:RabbitMQ 七战 Kafka,差异立现为什么阿里规定需要在事务注解@Transactional中指定rollbackFor?最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。明天见(。・ω・。)ノ♡

因用了Insert into select语句,美女同事被开除了!相关推荐

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

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

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

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

  3. SQL语句--INSERT INTO SELECT 语句用法示例

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

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

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

  5. insert into select语句锁表故障

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

  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 使用 参考源 简单教程 https://www.twle.cn/l/yufei ...

  9. INSERT INTO SELECT语句与SELECT INTO FROM语句区别

    1.INSERT INTO SELECT语句 语句形式为:Insert into Table2(field1,field2,-) select value1,value2,- from Table1 ...

  10. oracle中create table as和insert into select语句

    SELECT INTO , INSERT INTO SELECT 和 CREATE TABLE AS SELECT INSERT INTO SELECT Create table newTable a ...

最新文章

  1. 模型的可解释性:部分依赖图PDP和个体条件期望图ICE
  2. CES 2018即将揭幕:AI平台之争烽烟骤起
  3. 好东西和大家分享阿!
  4. Ansible16:Playbook高级用法
  5. Django模型(三)
  6. Python面试题之装饰器漫谈
  7. 百度面试题:从海量日志中提取访问百度次数最多的IP
  8. 如何“加密”你的email地址
  9. 树莓派开发界面显示温度_关于树莓派linux开发板
  10. javafx 菜单组件_基础6:新菜单组件
  11. 面试技巧:带走面试官的节奏
  12. 综合运用(烤地瓜,搬家具)
  13. Android8-Settings-BlueTooth
  14. Mac-如何在任意文件夹下打开终端
  15. uml通信图画法_[UML]UML系列——协作图(通信图)collaboration diagram
  16. IBM 中国研究院面试经历
  17. 【北亚服务器数据恢复】Infortrend ESDS系列服务器raid6数据恢复
  18. 重磅!继“智能+”120页PPT,阿里+毕马威发布4份智能经济报告(附免费下载)
  19. backgroundworker类
  20. 【UE4 第一人称射击游戏】20-添加瞄准十字线

热门文章

  1. react生命周期函数
  2. MySQL_数据库操作语句
  3. 【转】MFC消息映射详解(整理转载)
  4. Firefox3 RC1颁布各种新特征发扬阐发更平定
  5. [转]Windows与VC命名规则
  6. 【怎样写代码】函数式编程 -- Lambda表达式(二):C#常用委托
  7. 【C#串口编程计划】串口编程简介
  8. 【Codeforces】401C Team (01010110...)
  9. 终于有人把Python讲清楚了!
  10. AI进军服装零售产业:微软小冰与特步推出定制化服装设计生产及零售平台