Databases 7 min read

Why ‘INSERT INTO SELECT’ Can Crash Your MySQL Production – A Post‑mortem

A MySQL data‑migration using INSERT INTO SELECT caused massive payment‑record loss due to full‑table scans and lock contention, highlighting the need for proper indexing and awareness of transaction isolation when moving large datasets.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why ‘INSERT INTO SELECT’ Can Crash Your MySQL Production – A Post‑mortem

Background

In a company with a high‑traffic MySQL payment‑flow table, a data‑migration task was needed to move old records to a history table.

Two proposed solutions

Query data in the application, insert into the history table, then delete the original rows.

Use a single INSERT INTO ... SELECT statement to let MySQL handle the whole operation.

What went wrong

The first approach caused OOM when loading all rows at once; the second seemed to work in tests but caused massive data loss in production after the nightly job ran.

First approach code

// 1. Query data to migrate
List<Object> list = selectData();
// 2. Insert into history table
insertData(list);
// 3. Delete original rows
deleteByIds(ids);

The OOM was obvious because all data were loaded into memory.

Second approach

The team kept only the last ten days of data and executed:

INSERT INTO target_table SELECT * FROM source_table WHERE dateTime < DATE_SUB(NOW(), INTERVAL 10 DAY);

Testing with 10 k rows passed, and the job was scheduled at 20:00. However, after the job ran, many payment records failed to insert, leading to financial loss.

Root cause analysis

Explain plan showed a full‑table scan, which locked the source table under the default transaction isolation level (the a table was locked, b rows locked one by one). This caused intermittent lock time‑outs and insert failures.

Testing missed the issue because the test environment did not reproduce the large‑scale concurrent writes that occurred in production.

Solution

Avoid full‑table scans by adding appropriate indexes on the WHERE clause so the SELECT part uses an index.

Can INSERT INTO SELECT still be used?

Yes, but only with proper indexing and awareness of its locking behavior.

Takeaway

Use INSERT INTO SELECT cautiously; always ensure the query is indexed to prevent full‑table scans and lock contention.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performancemysqlINSERT INTO SELECTtransaction isolationdatabase indexing
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

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.