MySQL Insert Speeds Vary by 103x: The Same 100k Rows, Different Methods
Developers routinely leave 10x–100x on the table in MySQL ingest because they assume the database is the bottleneck. The measured truth is that per-SQL round trips, fsyncs, and naive ORM wrappers cost more than the row insertion itself.
A direct benchmark of 100k-row inserts into MySQL puts the slowest method (individual INSERT with a transaction per row) at 1,903 rows/s, and the fastest (LOAD DATA LOCAL INFILE) at 197,028 rows/s — a 103.5x spread. The bottleneck isn't the disk or database engine; it's how many times you talk to the server and how often you force an fsync.
Batch INSERT with 100–1000 rows per statement captures most of the gain, hitting about 70k rows/s. The jump from one row to ten yields 5.6x; beyond 100 rows, throughput plateaus. LOAD DATA skips SQL parsing and streaming builds indexes, which is why it reaches 2.8x even beyond well-tuned batch INSERT, but it trades strict file format and weaker error handling. Practical tips from the tests: drop secondary indexes before bulk loads, sort by primary key, verify that ORM "bulk" APIs actually emit multi-value INSERTs, and set rewriteBatchedStatements=true in JDBC to avoid silently falling back to single-row transactions.
The 2.5x fsync penalty is real, but it's a side show — the dominant cost is the fixed per-SQL overhead, which is why batching beats merely widening the transaction.
Because batch returns flatten at 100 rows, developers gain nothing from risking huge multi-megabyte statements; 100–1000 is the sweet spot for both performance and operational safety.
The ORM trap is the most expensive mistake in practice: code that looks like batching but still emits single-row INSERTs quietly leaves 10x on the table, and only query logging exposes it.
LOAD DATA's 2.8x advantage over even optimal batch INSERT shows that the SQL layer itself carries a heavy tax; formats that skip the parser are worth considering for any high-volume ingest path.
The main caveat — missing indexes and random primary keys can erase the entire gain from LOAD DATA — implies that physical layout and index strategy remain the real ceiling for write throughput, not the chosen insert syntax.
Batch size also needs to be considered together with row width and lock time cost.