2

データベーステーブルからの最大70万件のレコードを処理するレポートページがあります。結果を分割するためにページングを使用してこれをWebページに表示できます。ただし、PDF / CSV関数へのエクスポートは、データセット全体を一度に処理することに依存しており、約25万行で256MBのメモリ制限に達しています。

メモリ制限を増やすことに抵抗があり、MySQLの出力ファイルへの保存を使用して事前に生成されたCSVを提供する機能がありません。ただし、次のようなものを使用してDrupalで大規模なデータセットを提供する方法を実際に見ることはできません。

$form = array();
$table_headers = array();
$table_rows = array();
$data = db_query("a query to get the whole dataset");
while ($row = db_fetch_object($data)) {
    $table_rows[] = $row->some attribute;
}

$form['report'] = array('#value' => theme('table', $table_headers, $table_rows);
return $form;

アレイの巨大なアレイに本質的に追加されているものを回避する方法はありますか?現時点では、これが原因でDrupalで意味のあるレポートページを提供する方法がわかりません。

ありがとう

4

7 に答える 7

4

このような大規模なデータセットでは、時間のかかる操作をバッチに分割できるDrupalのBatchAPIを使用します。また、操作にかかる時間を示すプログレスバーが表示されるため、ユーザーにとっても便利です。

一時ファイルを開いてバッチ操作を開始し、完了するまで新しいバッチごとに新しいレコードを追加します。最終ページでは、データをcvsとして配信したり、PDFに変換したりするための最終処理を行うことができます。おそらく、クリーンアップのアフターワードも追加することをお勧めします。

http://api.drupal.org/api/group/batch/6

于 2010-03-19T16:43:01.600 に答える
1

PDFまたはCSVを生成している場合は、Drupalネイティブ関数を使用しないでください。whileループ内の出力ファイルへの書き込みはどうですか?このように、一度に1つの結果セットのみがメモリに存在します。

于 2010-03-19T12:32:43.580 に答える
0

現時点では、すべてを配列に格納しています$table_rows

一部のメモリを解放するために、データベースからレポートを読み取っているときに、レポートの少なくとも一部(たとえば、非常に多くの行)をフラッシュできませんか?一度にcsvにしか書き込めない理由がわかりません。

于 2010-03-19T12:31:15.173 に答える
0

メモリ制限を増やすのが苦手です

メモリ制限を増やしても、すべてのphpプロセスがその量のメモリを使用するわけではありません。ただし、カスタムメモリ制限を使用してPHPのCLIバージョンを実行することはできますが、それも適切な解決策ではありません。

MySQLの出力ファイルへの保存を使用して事前に生成されたCSVを提供する機能がありません

次に、すべてを配列に保存しないでください。データベースからフェッチするときに、各行を出力バッファーに書き込みます(IIRCでは、結果セット全体が制限されたphpメモリの外部にバッファリングされます)。または、ファイルに直接書き込み、ファイルが完成して閉じられたときにリダイレクトを実行します。

C。

于 2010-03-19T15:25:31.113 に答える
0

pager_queryを使用してページングを含め、結果をページごとに50〜100に分割する必要があります。それは大いに役立つはずです。ページングを使用したいとおっしゃっていますが、コードには表示されません。

これをチェックしてください:http://api.drupal.org/api/function/pager_query/6

于 2010-03-20T04:19:30.733 に答える
0

もう1つ覚えておくべきことは、PHP5(5.3より前)では、配列を新しい変数に割り当てるか、関数に渡すと、配列がコピーされ、参照が作成されないことです。同じデータのコピーを多数作成している可能性があります。未設定またはスコープ外のコピーがない場合、それらをガベージコレクションしてメモリを解放することはできません。可能な場合は、参照を使用して元の配列で操作を実行すると、メモリを節約できます

function doSomething($arg){
  foreach($arg AS $var)
    // a new copy is created here internally: 3 copies of data exist
    $internal[] = doSomethingToValue($var);
  return $internal;
  // $arg goes out of scope and can be garbage collected: 2 copies exist
}
$var = array();
// a copy is passed to function: 2 copies of data exist
$var2 = doSomething($var);
// $var2 will be a reference to the same object in memory as $internal, 
//  so only 2 copies still exist

$ varが関数の戻り値に設定されている場合、古い値はガベージコレクションできますが、割り当てが完了するまでは収集されないため、しばらくの間、より多くのメモリが必要になります。

function doSomething(&$arg){
  foreach($arg AS &$var)
    // operations are performed on original array data: 
    // only two copies of an array element exist at once, not the whole array
    $var = doSomethingToValue($var);  
  unset($var); // not needed here, but good practice in large functions
}
$var = array();
// a reference is passed to function: 1 copy of data exists
doSomething($var);
于 2010-03-21T03:19:23.423 に答える
0

私がそのような巨大なレポートにアプローチする方法は、php cli / Java / CPP / C#(つまり、CRONTAB)でレポートを生成し、mysqlが持つバッファなしのクエリオプションを使用することです。
ディスク上でファイル/レポートの作成が完了したら、そのディスクへのリンクを指定できます...

于 2010-03-21T03:23:46.363 に答える