INSERT 是 MySQL 最核心的寫入操作,但隨著數據量增長,單條插入性能瓶頸明顯。本文系統梳理 INSERT 語法變體、PHP/Java 客戶端調用、批次插入、事務優化、參數調優五大維度,提供從千條到億級寫入的完整優化路徑。
-- 標準語法
INSERT INTO table_name (col1, col2, ...) VALUES (val1, val2, ...);
-- 多行插入(單條 SQL)
INSERT INTO table_name (col1, col2) VALUES
('a', 1), ('b', 2), ('c', 3);
-- 插入查詢結果
INSERT INTO target_tbl (col1, col2) SELECT col1, col2 FROM source_tbl WHERE ...;
-- 忽略重複鍵錯誤
INSERT IGNORE INTO table_name ... VALUES ...;
-- 衝突時更新
INSERT INTO table_name ... VALUES ... ON DUPLICATE KEY UPDATE col2=VALUES(col2);
$stmt = $mysqli->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param("ss", $name, $email);
foreach ($batch as $row) {
$name = $row['name']; $email = $row['email'];
$stmt->execute();
}
$stmt->close();
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
for (User u : batch) {
ps.setString(1, u.getName());
ps.setString(2, u.getEmail());
ps.addBatch();
}
int[] results = ps.executeBatch(); // 一次網絡往返
}
-- 將 1000 條單行合併為 1 條 1000 行 SQL INSERT INTO tbl (a,b) VALUES (1,2), (3,4), ... (1999,2000);
限制:max_allowed_packet(默認 4MB/1MB),超大批次需分片
START TRANSACTION; INSERT ...; INSERT ...; ... (批次 1000-5000 行) COMMIT;
原理:InnoDB 預設 innodb_flush_log_at_trx_commit=1,每次提交刷盤。事務合併可將刷盤頻率降低 N 倍
LOAD DATA INFILE '/path/data.csv' INTO TABLE tbl FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES;
優勢:繞過 SQL 解析、索引逐行維護、WAL 寫入優化,**比 INSERT 快 10-20 倍**
前提:secure_file_priv 允許、文件在服務器本地、表無觸發器/外鍵
| 參數 | 建議值 | 影響 | 注意 |
|---|---|---|---|
| innodb_buffer_pool_size | 物理記憶體 60-75% | 數據/索引緩存核心 | 過大導致 Swap |
| innodb_log_file_size | 1-4 GB | Redo Log 容量,減少 Checkpoint 衝刷 | 修改需重啟、舊日誌備份 |
| innodb_log_buffer_size | 64-256 MB | 大事務/Blob 寫入緩衝 | 每秒刷盤,無需過大 |
| innodb_flush_log_at_trx_commit | 2 (高寫入) | 1=每提交刷盤;2=每秒刷盤;0=OS決定 | 2 可能丟失 1 秒數據 |
| sync_binlog | 100-1000 | Binlog 刷盤頻率 | 主從同步環境建議 1 |
| max_allowed_packet | 64-256 MB | 單條 SQL/包大小上限 | 客戶端同步修改 |
| bulk_insert_buffer_size | 64-256 MB | MyISAM 批量插入緩衝 | InnoDB 無效 |
SET autocommit=0,手動控制事務邊界ALTER TABLE ... DISABLE KEYS → 導入 → ENABLE KEYSmax_allowed_packet 調整LOAD DATA,線程數 = CPU 核心數Innodb_rows_inserted、Innodb_dml_latency、Innodb_log_waitsAUTO_INCREMENT 仍遞增,導致主鍵空洞CHARACTER SET utf8mb4,否則亂碼