Databases 6 min read

Why Using INSERT INTO SELECT Can Crash Your MySQL Production – A Real‑World Postmortem

A developer’s costly mistake using MySQL’s INSERT INTO SELECT for large data migration led to OOM, full-table scans, and lost payments, revealing how transaction locks and missing indexes can cause production failures and how to prevent them.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Why Using INSERT INTO SELECT Can Crash Your MySQL Production – A Real‑World Postmortem
血一般的教训,请慎用 insert into select。同事应用之后,导致公司损失了近10w元,最终被公司开除。

事情的起因

公司交易量大,使用 MySQL,每天增量约百万,未分库分表,需要通过数据迁移维持表性能。

同事李某提出两种方案:

先查询数据,插入历史表,再删除原表。

使用 INSERT INTO SELECT 让数据库 I/O 完成所有操作。

第一方案一次性加载导致 OOM,分批仍然 I/O 多且耗时,最终选择第二方案,测试无误后上线,却被开除。

到底发生了啥,我们复盘一下

先来看第一个方案,先看伪代码

// 1、查询对应需要迁移的数据
List<Object> list = selectData();

// 2、将数据插入历史表
insertData(list);

// 3、删除原表数据
deleteByIds(ids);

代码一次性把所有数据加载到内存,导致 OOM。

再来看看第二个方案,到底发生了啥。

为保留最近 10 天数据(约 1 万条),同事在 INSERT INTO SELECT 中加入时间筛选 dateTime < (Ten days ago) ,避免分页查询,消除了 OOM,并简化代码。

在测试环境使用 1 万条模拟数据,定时任务在晚上 8 点执行,测试通过。

但第二天财务对账发现支付流水缺失,排查后发现晚上 8 点后开始出现插入失败,导致大量数据丢失。

最终定位到迁移任务导致的问题,停掉任务后问题消失。

复盘

问题在哪里?

查看 INSERT INTO SELECT 的 EXPLAIN,发现全表扫描。

全表扫描在大表上会导致迁移时间长,白天未出现问题是因为迁移耗时约一小时,夜间任务与业务并发导致锁表。

原因

在默认事务隔离级别下,INSERT INTO SELECT 对目标表 a 加表锁,对源表 b 逐行加锁。逐行加锁时,支付流水表的复合记录被锁定,部分无法获取锁,导致超时或失败。

为什么测试没有问题?

测试使用的是真实数据量,但测试环境并未模拟大批量插入的并发场景,导致未暴露问题。

解决办法

避免全表扫描,对 WHERE 条件建立索引,使 SELECT 能走索引。

insert into 还能用吗?

可以,但必须做好索引和锁控制。

总结

使用 INSERT INTO SELECT 时务必慎重,确保有合适的索引以避免全表扫描和锁表导致的生产事故。

MySQLINSERT INTO SELECTtransaction isolationDatabase PerformanceFull Table Scan
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.