向空表插入200萬條資料,三種方案耗時對比:
效能差距超120倍,本文深度剖析原理與最佳實踐。
CREATE TABLE example (
example_id INT NOT NULL,
name VARCHAR(50) NOT NULL,
value VARCHAR(50) NOT NULL,
other_value VARCHAR(50) NOT NULL
);
for ($i=0; $i<2000000; $i++) {
$connect_mysql->insert(['value' => '50']);
}
缺陷:每條SQL獨立解析、優化、執行、提交;網路往返+事務開銷巨大;PHP端循環開銷額外增加。
$connect_mysql->query('BEGIN');
for ($i=0; $i<2000000; $i++) {
$connect_mysql->insert(['value' => '50']);
if ($i % 100000 == 0) {
$connect_mysql->query('COMMIT');
$connect_mysql->query('BEGIN');
}
}
$connect_mysql->query('COMMIT');
優勢:減少事務提交次數(20次 vs 200萬次),利用InnoDB redo log批次刷盤。
劣勢:仍發送200萬條獨立SQL,網路協議解析開銷大。
$sql = "INSERT INTO twenty_million (value) VALUES ";
for ($i=0; $i<2000000; $i++) {
$sql .= "('50'),";
}
$sql = substr($sql, 0, -1); // 移除尾部逗號
$connect_mysql->query($sql);
關鍵配置:需調大max_allowed_packet(如SET GLOBAL max_allowed_packet = 20M),否則大SQL會被截斷報錯。
原理:單次網路往返、單次解析優化、單次事務提交、InnoDB批次寫入change buffer+刷盤,效能極致。
| 場景 | 推薦方案 | 注意事項 |
|---|---|---|
| 業務實時寫入、高併發 | 方案二(事務批次) | 批次大小1000-5000,避免長事務鎖爭用 |
| 資料遷移、初始化、離線導入 | 方案三(多值SQL) | 分批次(如每5萬行),控制SQL長度與記憶體 |
| 異構資料同步、ETL | LOAD DATA INFILE | 比INSERT快10倍+,需檔案權限 |
SET UNIQUE_CHECKS=0(導入後重開)SET FOREIGN_KEY_CHECKS=0選對方案,百萬級插入從「小時級」降為「分鐘級」,甚至「秒級」。