| 階段 | 工具 | 操作 |
| 導出結構 | phpMyAdmin | 「導出」→ 選「結構」→ 保存 schema.sql |
| 導出數據 | PHP 腳本 | 逐行讀取表數據 → 文本文件 table.txt(每行一字段,特殊字符轉義) |
| 導入結構 | phpMyAdmin | 「導入」schema.sql 重建表結構 |
| 導入數據 | PHP 腳本 | 讀取 table.txt → 反轉義 → 批量 INSERT |
導出腳本:export_table.php
<?php
// 用法:export_table.php?table=tablename
$table = $_GET['table'] ?? exit('Missing table param');
$conn = mysqli_connect('localhost', 'user', 'pass', 'db') or die('Connect failed');
mysqli_set_charset($conn, 'utf8');
$res = mysqli_query($conn, "SELECT * FROM `$table`");
if (mysqli_num_rows($res) === 0) exit('Empty table');
echo "開始導出數據到文本...\n";
$fp = fopen("$table.txt", 'w');
$fieldCount = mysqli_num_fields($res);
fwrite($fp, $fieldCount . "\r\n"); // 首行寫字段數
$placeholder = "&&PHP2000MySQLreturn&&"; // 換行符佔位符
while ($row = mysqli_fetch_row($res)) {
for ($i = 0; $i < $fieldCount; $i++) {
// 轉義換行符,防止文本行結構破壞
$row[$i] = str_replace(["\r\n", "\n"], $placeholder, $row[$i]);
fwrite($fp, $row[$i] . "\r\n");
}
fwrite($fp, "------- PHP2000 dump data program V1.0 for MySQL --------\r\n"); // 行分隔符
}
fclose($fp);
echo "ok";
?>
導入腳本:import_table.php
<?php
$table = $_GET['table'] ?? exit('Missing table param');
$conn = mysqli_connect('localhost', 'user', 'pass', 'db') or die('Connect failed');
mysqli_set_charset($conn, 'utf8');
$lines = file("$table.txt", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (!$lines) exit('File empty');
$fieldCount = (int)$lines[0];
$placeholder = "&&PHP2000MySQLreturn&&";
$rowDelimiter = "------- PHP2000 dump data program V1.0 for MySQL --------";
$values = [];
$rowData = [];
$lineIdx = 1;
while ($lineIdx < count($lines)) {
$line = $lines[$lineIdx++];
if ($line === $rowDelimiter) {
// 一行數據讀完,構建 INSERT
$escaped = array_map(fn($v) => "'" . mysqli_real_escape_string($conn, str_replace($placeholder, "\n", $v)) . "'", $rowData);
$values[] = '(' . implode(',', $escaped) . ')';
$rowData = [];
continue;
}
$rowData[] = $line;
if (count($rowData) === $fieldCount) {
// 正常應在分隔符前湊齊,這裡作為兜底
}
}
// 批量插入(每 500 行一條 SQL,防止過長)
$batchSize = 500;
for ($i = 0; $i < count($values); $i += $batchSize) {
$batch = array_slice($values, $i, $batchSize);
$sql = "INSERT INTO `$table` VALUES " . implode(',', $batch);
if (!mysqli_query($conn, $sql)) {
die("Insert failed at batch $i: " . mysqli_error($conn));
}
}
echo "Import completed: " . count($values) . " rows.\n";
?>
關鍵設計細節
- 逐行一字段:避免 CSV 分隔符衝突,天然支持任意文本內容(含逗號、引號、換行)。
- 佔位符轉義:
\r\n/\n → &&PHP2000MySQLreturn&&,導入時還原。
- 行分隔符:固定特征字符串標記行邊界,解析邏輯極簡健壯。
- 首行字段數:自適應表結構變更,導入端無需硬編碼。
- 批量 INSERT:500 行一批,平衡 SQL 長度與網絡往返開銷。
- mysqli_real_escape_string:導入時二次轉義,防注入並處理引號。
擴展建議:生產級遷移工具鏈
- mysqldump + 管道壓縮:
mysqldump -u root -p --single-transaction --quick --hex-blob db | gzip > db.sql.gz,導入 zcat db.sql.gz | mysql -u root -p db,官方標準、支持並行、事務一致性。
- mydumper/myloader:多線程並行導出導入,大表自動切塊,速度提升 5-10 倍。
- CDC 同步:Canal/Debezium 捕獲 Binlog 實時同步異構目標,零停機遷移。
總結
phpMyAdmin 適合小表可視化操作;大數據量遷移必須繞過 HTTP/ PHP 限制,採用「結構與數據分離、文本流式處理、批量寫入」的工程化方案。上述腳本為教學級演示,生產環境請優先使用 mysqldump/mydumper 或 CDC 工具,獲得事務一致性、斷點續傳、並行加速等企業級能力。
- 上一篇文章: SQL 語句性能調優核心原則:WHERE 子句寫法決定索引成敗
- 下一篇文章: SQL Server 鏈接服務器調用遠程存儲過程:配置與實戰代碼
Copyright ©
程式碼之家 All Rights Reserved