面試高頻題:「如何高效向 MySQL 插入 10 萬/100 萬條數據?」本文實測三種主流方案,揭示多值 INSERT + 批量提交為性能王者,並分析核心優化原理。
id BIGINT PK, create_time DATETIME, random DOUBLEpublic void batchInsertMultiValues(Connection conn) throws SQLException {
String prefix = "INSERT INTO tb_big_data (count, create_time, random) VALUES ";
conn.setAutoCommit(false);
try (PreparedStatement pst = conn.prepareStatement("")) {
StringBuilder suffix = new StringBuilder();
for (int batch = 1; batch <= 100; batch++) {
suffix.setLength(0);
for (int i = 1; i <= 10000; i++) {
long val = (long) batch * i;
suffix.append("(").append(val).append(", NOW(), ").append(val * Math.random()).append("),");
}
// 去掉末尾逗號
String sql = prefix + suffix.substring(0, suffix.length() - 1);
pst.addBatch(sql);
pst.executeBatch(); // 執行批次
conn.commit(); // 提交事務
}
}
}
// 耗時:~23 秒(含網絡延遲),單批 1 萬行約 0.23s
public void batchInsertParamBinding(Connection conn) throws SQLException {
String sql = "INSERT INTO tb_big_data (count, create_time, random) VALUES (?, NOW(), ?)";
conn.setAutoCommit(false);
try (PreparedStatement pst = conn.prepareStatement(sql)) {
for (int batch = 1; batch <= 100; batch++) {
for (int i = 1; i <= 10000; i++) {
long val = (long) batch * i;
pst.setLong(1, val);
pst.setDouble(2, val * Math.random());
pst.addBatch();
}
pst.executeBatch();
conn.commit();
}
}
}
// 耗時:~111 秒,方案一的 5 倍
addBatch,但 每行仍發送一次參數包,網絡包數量 = 行數jdbcTemplate.batchUpdate(
"INSERT INTO tb_big_data (count, create_time, random) VALUES (?, NOW(), ?)",
new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setLong(1, i);
ps.setDouble(2, i * Math.random());
}
public int getBatchSize() { return 10000; }
});
// 耗時:~387 秒(僅測 1 萬條),效率最低
| 優化點 | 方案一 | 方案二 | 方案三 |
|---|---|---|---|
| SQL 解析次數 | 100 次(批次數) | 1 次(預編譯) | 1 次 |
| 網絡往返 | 100 次 | 100 次 | 100 次 |
| 網絡包大小 | 大(含完整 SQL) | 小(僅參數) | 小 |
| 服務端 CPU | 低(批量執行) | 高(逐行綁定) | 高 |
| 事務提交 | 100 次 | 100 次 | 100 次 |
| 適用場景 | 大批量導入 | 中等批量、參數化需求 | 業務代碼統一、小批量 |
conn.setAutoCommit(false) 必須,手動分批提交DROP INDEX,導入後 CREATE INDEX,大表提速 3-5 倍innodb_buffer_pool_size、innodb_log_file_size、innodb_flush_log_at_trx_commit=2(導入期可暫時放寬)方案一(多值 INSERT + 批量提交)是百萬級插入的性能王者。核心原理:最小化網絡往返、最大化服務端批量處理效率。Spring 專案中可提取為工具類,不依賴框架批量 API。