PHPアプリケーションにおける大規模Excelデータの高速エクスポート手法: XLSWriterの実装と最適化

10万行を超える大規模データセットをExcel形式でエクスポートする際、PHPアプリケーションではメモリ使用量と処理時間が主要な課題となります。XLSWriter拡張モジュールを活用することで、効率的なデータ処理が実現可能です。この拡張モジュールはPECLパッケージとして提供され、PHP 8環境での動作をサポートしています。Windows開発環境では事前ビルド済みDLLが利用可能で、設定が容易です。初回実行時は多少遅延しますが、OPcacheを有効化することで以降の実行が高速化されます。

チャンク処理を実装したエクスポートコード

以下はLaravelフレームワークで実装した最適化コード例です。メモリ制限を適切に設定し、データをチャンク単位で処理することで、メモリ使用量を制御しています。

ini_set('memory_limit', '1024M');

$exportConfig = [
    'path' => storage_path('exports')
];
$workbook = new \Vtiful\Kernel\Excel($exportConfig);
$dataSheet = $workbook->fileName('bulk_export.xlsx', 'Records')
    ->header([
        'ID', '氏名', '電話番号', 'データソース', 
        '都道府県', '市区町村', '記録日時', 
        'ユーザID', 'ニックネーム', '登録日時',
        '上位ユーザID', '店舗名', '新規フラグ'
    ]);

\App\Models\CustomerRecord::chunk(8000, function ($records) use ($dataSheet) {
    foreach ($records as $record) {
        $rowData = [
            $record->id,
            $record->full_name,
            $record->contact_number,
            $record->source_type,
            $record->prefecture,
            $record->municipality,
            $record->record_timestamp,
            $record->user_id,
            $record->alias,
            $record->registration_date,
            $record->referrer_id,
            $record->store_title,
            $record->is_new_flag
        ];
        $dataSheet->insertRow($rowData);
    }
});

$exportPath = $dataSheet->output();

パフォーマンス測定結果

115,135件のデータセットを処理した際のベンチマーク結果を表にまとめます。チャンクサイズの変更がメモリ使用量と処理時間に与える影響を確認しています。

チャンクサイズ 処理時間 ピークメモリ
20,000 16秒 53.15 MB
15,000 15秒 37.00 MB
8,000 20秒 20.82 MB
10,000 15秒 42.99 MB

代替手法の検証

大規模データエクスポートには以下の代替手法も検討可能です。

CSVストリーミング方式

出力バッファを定期的にフラッシュする手法です。シンプルなフォーマットに適しますが、書式設定が複雑なExcelファイルには対応できません。

$stream = fopen('php://output', 'w');
fputcsv($stream, ['メールアドレス']);

$counter = 0;
$flushThreshold = 10000;

\App\Models\UserProfile::chunk($flushThreshold, function ($profiles) use ($stream, $flushThreshold, &$counter) {
    foreach ($profiles as $profile) {
        $counter++;
        if ($counter % $flushThreshold === 0) {
            ob_flush();
            flush();
        }
        fputcsv($stream, [$profile->email]);
    }
});
fclose($stream);

SQLネイティブエクスポート

MySQLのINTO OUTFILE機能を直接利用する方法です。データベースサーバー負荷が低く高速ですが、ファイルシステム権限が必要です。

SELECT id, full_name, contact_number, ...
INTO OUTFILE '/var/export/data.csv'
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM customer_records;

非同期キュー処理

エクスポートタスクをRedisやMQキューに投入し、CLI環境でバックグラウンド実行します。リクエストタイムアウトのリスクを回避できますが、実装コストが増加します。

マルチファイル分割方式

データを複数のExcelファイルに分割して出力し、必要に応じてマージする手法です。メモリ負荷を分散できますが、ディスクI/Oが増加するデメリットがあります。

タグ: XLSWriter PHP laravel MySQL memory optimization

5月22日 09:20 投稿