数万件のDBレコードをローカル(XAMPP)からVPSへ高速同期する方法

PHP

開発環境(Local)でスクレイピングやAIによるデータ加工を行い、完成したデータを本番環境(VPS)へ反映させる際、数万件規模になると通常のインポート/エクスポートでは手間がかかり、タイムアウトのリスクも伴います。

今回は、PHPのcURLを用いた「チャンク(分割)送信」により、巨大なデータを安全に同期する仕組みを構築しました。


1. 構成の概要

ローカル側に「送信スクリプト」、VPS側に「データ受信用API」を設置します。 一度に全データを送るとサーバーのPOST制限に抵触するため、1,000件ずつの塊(チャンク)にして連続送信するのがポイントです。


2. VPS側:データ受信API (api_sync_db.php)

VPS側のディレクトリ(例: /var/www/html/project/api_sync_db.php)に配置します。

  • 役割: 送られてきた分割データを受け取り、DBに書き込む。

  • ポイント: 各テーブルの最初のデータ(is_first)が届いた時だけ TRUNCATE(テーブル初期化)を行い、残りは INSERT していきます。

<?php set_time_limit(0); // 処理時間を無制限に ini_set('memory_limit', '512M'); // DB接続設定 define('DB_HOST', 'localhost'); define('DB_USER', 'your_user'); define('DB_PASS', 'your_password'); define('DB_NAME', 'your_db_name'); define('SYNC_TOKEN', 'your_secure_token'); // 認証用の合言葉 try { $pdo = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4", DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]);
} catch (PDOException $e) {
    http_response_code(500);
    exit('DB Connection Error');
}

// トークンチェック
if (($_POST['token'] ?? '') !== SYNC_TOKEN) {
    http_response_code(403);
    exit('Forbidden');
}

$table = $_POST['table'] ?? '';
$is_first_chunk = ($_POST['is_first'] === '1');
$rows = json_decode($_POST['data'], true);

try {
    $pdo->exec("SET FOREIGN_KEY_CHECKS = 0"); // 外部キー制約を一時解除

    if ($is_first_chunk) {
        $pdo->exec("TRUNCATE TABLE `$table` "); // 初回のみテーブルを空に
    }

    if (!empty($rows)) {
        $columns = array_keys($rows[0]);
        $colNames = "`" . implode("`, `", $columns) . "`";
        $placeholders = implode(", ", array_fill(0, count($columns), "?"));
        $stmt = $pdo->prepare("INSERT INTO `$table` ($colNames) VALUES ($placeholders)");

        foreach ($rows as $row) {
            $stmt->execute(array_values($row));
        }
    }

    $pdo->exec("SET FOREIGN_KEY_CHECKS = 1");
    echo "Success: Chunk processed for $table";
} catch (Exception $e) {
    http_response_code(500);
    echo "Sync Error: " . $e->getMessage();
}

3. ローカル側:分割送信スクリプト (db_push_to_vps.php)

XAMPPのプロジェクトルートに配置し、ブラウザまたはCLIから実行します。

  • 役割: ローカルDBから全データを取得し、1,000件単位でVPSへPOST。

  • メリット: 万が一途中で失敗しても、どのチャンクで止まったか把握しやすい。

<?php set_time_limit(0); ini_set('memory_limit', '1024M'); // ローカルDB設定 define('L_DB_HOST', 'localhost'); define('L_DB_USER', 'root'); define('L_DB_PASS', '0000'); define('L_DB_NAME', 'your_db_name'); // 送信先URLと設定 $vps_url = "http://your-vps-ip/project/api_sync_db.php"; $token = "your_secure_token"; $chunk_size = 1000; try { $pdo = new PDO("mysql:host=".L_DB_HOST.";dbname=".L_DB_NAME.";charset=utf8mb4", L_DB_USER, L_DB_PASS, [ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]);
} catch (PDOException $e) {
    exit('Local DB Error');
}

// 同期対象テーブル
$tables = ['products', 'actresses', 'genres', 'rewritten_titles', 'product_screenshots'];

foreach ($tables as $table) {
    echo "Synchronizing $table...\n";
    $stmt = $pdo->query("SELECT * FROM `$table` ");
    $all_rows = $stmt->fetchAll();
    
    $chunks = array_chunk($all_rows, $chunk_size);
    foreach ($chunks as $index => $chunk) {
        $post_data = [
            'token'    => $token,
            'table'    => $table,
            'is_first' => ($index === 0) ? '1' : '0',
            'data'     => json_encode($chunk)
        ];

        // cURLで送信
        $ch = curl_init($vps_url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);
        
        echo "."; // 進捗ドット
    }
    echo " Done!\n";
}

4. まとめ:なぜこの方法が優れているか

  1. タイムアウト回避: 1回のリクエストを小さくすることで、サーバー側の負荷を分散できます。

  2. 容量制限を突破: post_max_size が8MB程度の標準設定でも、数万件(数十MB分)のデータを確実に送れます。

  3. 完全同期: TRUNCATE 方式を採用しているため、ローカルで削除したレコードもVPS側に反映されます。

数万件のデータ移動に悩んでいる方は、ぜひこのAPIベースの同期を試してみてください。

コメント

タイトルとURLをコピーしました