海量數據導入是 MySQL 運維高頻場景。本文系統對比單行 INSERT、批次 INSERT、LOAD DATA INFILE、禁用索引、鎖表、分區並行等 6 大優化策略,實測 LOAD DATA 比單行 INSERT 快 20 倍以上,並給出生產環境標準化導入 SOP。
| 層級 | 策略 | 相對速度 | 適用場景 | 核心原理 |
|---|---|---|---|---|
| 1 | 單行 INSERT | 1x (基線) | 極小量、業務實時寫入 | 每行解析、優化、執行、提交、刷盤 |
| 2 | 批次 INSERT (多值) | 5-10x | 應用層批量提交、中等量級 | 單次解析優化、單次提交、單次索引刷盤 |
| 3 | INSERT DELAYED | 異步 | 異構來源、可容忍延遲/丟失 | 隊列緩存,後台線程批量寫入(MySQL 8.0 移除) |
| 4 | LOAD DATA INFILE | 20-50x | 大批量離線導入、初始化、遷移 | 繞過 SQL 層、直接存儲引擎 API、批量構建索引頁 |
| 5 | 禁用索引 + LOAD DATA + 重建索引 | 50-100x | 巨量導入(億級)、MyISAM/InnoDB | 避免逐行索引維護,排序後批量建樹(更平衡) |
| 6 | 鎖表/事務批量 + 並行分區導入 | 100x+ | 極致性能、分庫分表架構 | 減少鎖開銷、並行寫入不同分區/實例 |
-- 單條 SQL 插入多行
INSERT INTO `t` (a, b, c) VALUES
(1, 'x', 100),
(2, 'y', 200),
(3, 'z', 300)
-- 批次大小建議 1000-5000 行,SQL 長度受 max_allowed_packet 限制(默認 4MB/64MB)
-- 配合 bulk_insert_buffer_size(MyISAM 專用,InnoDB 無效)
SET GLOBAL bulk_insert_buffer_size = 256*1024*1024;
-- 基本語法
LOAD DATA INFILE '/path/to/data.txt'
INTO TABLE `t`
FIELDS TERMINATED BY '\t' -- 欄位分隔符
ENCLOSED BY '"' -- 包圍符
ESCAPED BY '\\' -- 轉義符
LINES TERMINATED BY '\n' -- 行分隔符(Windows \r\n)
IGNORE 1 LINES -- 跳過標題行
(col1, col2, @var1, col3) -- 列映射,支持變量預處理
SET col3 = STR_TO_DATE(@var1, '%Y-%m-%d'); -- 導入時轉換
-- 本地文件導入(客戶端文件,需 LOCAL 權限)
LOAD DATA LOCAL INFILE '/local/path/data.txt' INTO TABLE `t` ...
關鍵參數:
local_infile=1(客戶端與服務端均需開啟)。secure_file_priv 限制服務端文件讀取目錄(非 LOCAL 模式)。character_set_database 一致,或指定 CHARACTER SET utf8mb4。-- 1. 僅建表結構,不建索引(或刪除現有索引)
CREATE TABLE `t` (...); -- 無 KEY 定義
-- 或
ALTER TABLE `t` DISABLE KEYS; -- MyISAM 專用,InnoDB 不支持
-- 2. 導入數據
LOAD DATA INFILE '...' INTO TABLE `t` ...;
-- 3. 重建索引
-- MyISAM
ALTER TABLE `t` ENABLE KEYS; -- 內存排序後批量建樹,極快
-- InnoDB
CREATE INDEX idx_a ON `t`(a);
CREATE INDEX idx_b ON `t`(b);
-- InnoDB 5.7+ 支持 ALGORITHM=INPLACE, LOCK=NONE 在線建索引
原理:逐行插入時,B+Tree 頻繁分裂/合併、隨機 IO;批量建樹先收集鍵值、內存排序、順序寫入葉子頁,零分裂、零碎片、索引完美平衡。
PARTITION BY RANGE/HASH)或分庫分表。LOAD DATA 寫入不同分區/實例。innodb_parallel_read_threads (8.0.14+) 支持並行掃描,導入階段亦受益。-- InnoDB 事務批量
START TRANSACTION;
INSERT INTO `t` VALUES ...; -- 批次 1
INSERT INTO `t` VALUES ...; -- 批次 2
...
COMMIT; -- 單次刷盤、單次 Binlog 寫入
-- 批次大小控制:避免超大事務導致 Undo Log 膨脹、鎖持有時間過長
-- 建議每 1000-5000 行或 10-50MB 提交一次
Innodb_rows_inserted、Threads_running、磁盤 IO、主從 Seconds_Behind_Master。utf8mb4 或顯式指定 CHARACTER SET。\r\n、Linux \n,LINES TERMINATED BY 必須匹配,否則導入行數錯誤/數據截斷。REPLACE/IGNORE 關鍵字控制衝突行行為。AUTO_INCREMENT 自動分配;若文件含主鍵需顯式列映射。MySQL 大批量插入極限優化路徑:
單行 INSERT → 批次 INSERT → LOAD DATA INFILE → 禁用索引+LOAD DATA+重建索引 → 並行分區導入。
核心槓桿:減少 SQL 解析優化次數、減少提交刷盤次數、避免逐行索引維護、利用順序 IO 批量構建索引。
生產環境首選 LOAD DATA INFILE + 事務分批提交,兼顧速度、安全、可運維。