各レコードに無制限のカスタム フィールド (EAV モデル、これは関係ありません) を含めることができ、各フィールドに無制限のオプションを含めることができ、各オプションに無制限の値を含めることができる mysql テーブルがあります。
現在、これらすべてのカスタム フィールドを値とともにエクスポートするエクスポート ツールを構築しようとしています。つまり、各フィールドの名前 => 値のペアです。それは重要な部分ではありません。単一のレコードに対する多数の mysql クエリについて話していること、およびエクスポートのサイズがかなり大きくなることを強調するためにここにいます。
メイン テーブルの行ごとに、約 100 の個別の SQL クエリを実行して、フィールド、フィールド オプション、およびフィールド オプションの値を取得する必要があります。これらのクエリはすべて適切なインデックスを使用しているため非常に高速ですが、それでも 1 つのレコードに対して 100 件のクエリについて話しているため、最初はメイン テーブルに約 50,000 件のレコードがあると予想されます。
今、私がしていることは次のとおりです。
set_time_limit(0);
ini_set('memory_limit', '1G');
ini_set("auto_detect_line_endings", true);
$count = $export->count();
$date = date('Y-m-d-H-i-s');
$fileName = CHtml::encode($export->name) .'-'. $date . '.csv';
$processAtOnce = 100;
$rounds = round($count / $processAtOnce);
header("Content-disposition: attachment; filename={$fileName}");
header("Content-Type: text/csv");
$headerSet = false;
for ($i = 0; $i < $rounds; ++$i) {
$limit = $processAtOnce;
$offset = $i * $processAtOnce;
$rows = $export->find($limit, $offset);
if (empty($rows)) {
continue;
}
$outStream = fopen('php://output', 'w');
if (!$headerSet) {
fputcsv($outStream, array_keys($rows[0]), ',', '"');
$headerSet = true;
}
foreach ($rows as $row) {
fputcsv($outStream, array_values($row), ',', '"');
}
echo fgets($outStream);
fclose($outStream);
}
基本的に、私はすべてのレコードを数え、エクスポートのためにそれらを「ページ分割」し、ページを実行して、一度に多くのSQL結果をロードしないようにします。
これが有効なアプローチであるかどうか疑問に思っていますか?何かご意見は?
私の代替手段は、すべてのレコードを数え、それらを「ページ」に分割し、各ページに対して ajax リクエスト (前のリクエストが正常に行われた後に呼び出される再帰関数) を実行することです。ajax リクエストを実行するときは、おそらく 1k レコードを一度に処理し (これらの 1k も上記の例のように分割され、内部で 10 回実行されて 100 の結果が得られます)、それらを一時ディレクトリ (part-1.csv など) に書き込みます。 part-2.csv) を作成し、最後にすべてのレコードが処理されたら、すべての csv パーツを含むフォルダーからアーカイブを作成し、ブラウザーに強制的にダウンロードさせてからサーバーから削除します (window.location.href 内から最後の ajax 呼び出し)。
これは上記の良い代替手段ですか?
私の目標はメモリ使用量を制限することです。そのため、2番目のアプローチがより役立つと思います。
ご意見をお聞かせください。
ありがとう。