MySQL 支援直接用一條 SQL 將查詢結果寫入目標表,是批量匯入最高效、最常用的方式。
INSERT INTO `target_table`
SELECT * FROM `source_table`;
INSERT INTO `target_table` (`col1`, `col2`, `col3`)
SELECT `col1`, `col2`, `col3`
FROM `source_table`
WHERE `status` = 1; -- 可加條件篩選
注意:來源與目標欄位順序、數量、型別必須一致,否則會報錯或資料截斷。
INSERT INTO `db_target`.`target_table` (`col1`, `col2`)
SELECT `col1`, `col2`
FROM `db_source`.`source_table`;
SET autocommit = 0;
INSERT INTO `target` SELECT * FROM `source` WHERE ...;
COMMIT;
減少磁碟 I/O,匯入百萬筆資料可提升 10~50 倍速度。
建議每 5,000~10,000 筆提交一次:
-- 假設有主鍵 id 可做分頁
INSERT INTO `target` SELECT * FROM `source` WHERE `id` BETWEEN 1 AND 10000;
COMMIT;
INSERT INTO `target` SELECT * FROM `source` WHERE `id` BETWEEN 10001 AND 20000;
COMMIT;
-- ...
ALTER TABLE `target` DISABLE KEYS; -- MyISAM 專用
-- 大量 INSERT ...
ALTER TABLE `target` ENABLE KEYS;
InnoDB 無 DISABLE KEYS,但可先刪除非唯一索引,匯入完成後重建:
ALTER TABLE `target` DROP INDEX `idx_name`;
-- 大量 INSERT ...
ALTER TABLE `target` ADD INDEX `idx_name` (`col`);
LOAD DATA INFILE '/path/to/data.csv'
INTO TABLE `target`
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(`col1`, `col2`, `col3`);
FILE 權限與 secure_file_priv 目錄許可# 來源伺服器導出並直接管線導入目標伺服器
mysqldump -h source_host -u user -p --single-transaction --quick db_name table_name \
| mysql -h target_host -u user -p db_name
--single-transaction:InnoDB 一致性備份不鎖表--quick:逐行串流,低記憶體-- 在目標伺服器建立映射表
CREATE TABLE `remote_table` (
`id` INT NOT NULL,
`data` VARCHAR(255)
) ENGINE=FEDERATED
CONNECTION='mysql://user:pass@source_host:3306/db_name/table_name';
-- 現在可直接查詢/寫入遠端表
INSERT INTO `local_table` SELECT * FROM `remote_table` WHERE ...;
限制:不支援事務、DDL、索引維護成本高、網路延遲敏感。
| 錯誤 | 原因 | 解決 |
|---|---|---|
| Duplicate entry 'xxx' for key 'PRIMARY' | 主鍵衝突 | 使用 INSERT IGNORE、REPLACE INTO 或 ON DUPLICATE KEY UPDATE |
| Data truncated for column 'col' | 欄位長度/型別不符 | 檢查來源資料範圍,調整目標欄位定義 |
| Lock wait timeout exceeded | 大事務鎖定過久 | 拆小批次、優化索引、調大 innodb_lock_wait_timeout |
| The used command is not allowed with this MySQL version | LOAD DATA INFILE 被禁用 | 啟用 local_infile=1 或改用 mysqlimport / 程式語言讀檔入庫 |
import pymysql
conn = pymysql.connect(host='localhost', user='root', password='pass', db='db', charset='utf8mb4')
cursor = conn.cursor()
batch_size = 5000
sql = "INSERT INTO `target` (`col1`, `col2`) VALUES (%s, %s)"
for i in range(0, len(data_list), batch_size):
batch = data_list[i:i+batch_size]
cursor.executemany(sql, batch)
conn.commit()
print(f"已寫入 {i+len(batch)} 筆")
cursor.close()
conn.close()
$pdo = new PDO("mysql:host=localhost;dbname=db;charset=utf8mb4", 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$batchSize = 5000;
$stmt = $pdo->prepare("INSERT INTO `target` (`col1`, `col2`) VALUES (?, ?)");
foreach (array_chunk($dataList, $batchSize) as $batch) {
$pdo->beginTransaction();
foreach ($batch as $row) {
$stmt->execute([$row['col1'], $row['col2']]);
}
$pdo->commit();
echo "已寫入 " . count($batch) . " 筆\n";
}
INSERT ... SELECT 最簡單mysqldump | mysql 管線最穩健LOAD DATA INFILE 或專業 ETL/CDC 工具