適用場景
- phpMyAdmin 匯入超時、記憶體不足、權限不足(無
LOCK TABLES)。
- 大型 SQL 檔(>50 MB)建議走命令列。
PHP 包裝腳本 (sql.php)
<?php
// 配置區
$dbHost = 'localhost';
$dbUser = 'root';
$dbPass = 'mypassword';
$dbName = 'database';
$sqlFile = __DIR__ . '/a.sql';
// 構建命令
$cmd = sprintf(
'mysql -h%s -u%s -p%s %s < %s 2>&1',
escapeshellarg($dbHost),
escapeshellarg($dbUser),
escapeshellarg($dbPass),
escapeshellarg($dbName),
escapeshellarg($sqlFile)
);
// 執行並捕獲輸出
$output = [];
$returnVar = 0;
exec($cmd, $output, $returnVar);
if ($returnVar === 0) {
echo "SQL 匯入成功\n";
} else {
echo "SQL 匯入失敗 (code {$returnVar}):\n";
echo implode("\n", $output);
}
安全強化
- 不要直接暴露:放在非公開目錄,或加入 IP 白名單、Token 驗證。
- 密碼不入日誌:使用
--defaults-extra-file 指向只讀的 .my.cnf:
[client]
host=localhost
user=root
password=mypassword
$cmd = "mysql --defaults-extra-file=/path/.my.cnf {$dbName} < " . escapeshellarg($sqlFile);
進階:分批匯入大檔
// 使用 sed/awk 分割大 SQL,或使用 PHP 逐行讀取執行
$fp = fopen('huge.sql', 'r');
$buffer = '';
$pdo = new PDO("mysql:host={$dbHost};dbname={$dbName}", $dbUser, $dbPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
while (($line = fgets($fp)) !== false) {
$buffer .= $line;
if (substr(trim($line), -1) === ';') { // 簡易語句結束判斷
try {
$pdo->exec($buffer);
} catch (PDOException $e) {
error_log("SQL Error: " . $e->getMessage() . "\nSQL: " . $buffer);
}
$buffer = '';
}
}
fclose($fp);
替代工具推薦
- MySQL Shell:
mysqlsh --sql -u root -p --file huge.sql 並行匯入更快。
- Percona Toolkit:
pt-fifo-split 分割 + 並行載入。
- LOAD DATA INFILE:針對純資料表,速度最快。