2

以下の関数を使用して、テーブルから行を取得し、エンコードしてから、csv形式で配置しています。高いメモリ使用量を防ぐためのより簡単な方法があるかどうか疑問に思っています。ini_setに依存する必要はありません。メモリの消費は、一時ファイルを読み取ってそれを圧縮することによって引き起こされると思います。64MBのRAMを使用できるようにしたいと思います。何か案は?ありがとう!

function exportcsv($tables) {
    foreach ($tables as $k => $v) {
        $fh = fopen("php://temp", 'w');
        $sql = mysql_query("SELECT * FROM $v");
        while ($row = mysql_fetch_row($sql)) {
            $line = array();
            foreach ($row as $key => $vv) {
                $line[] = base64_encode($vv);
            }
            fputcsv($fh, $line, chr(9));
        }
        rewind($fh);
        $data = stream_get_contents($fh);
        $gzdata = gzencode($data, 6);
        $fp = fopen('sql/'.$v.'.csv.gz', 'w');
        fwrite($fp, $gzdata);
        fclose($fp);
        fclose($fh);
    }
}
4

4 に答える 4

2

を介してファイル全体をメモリにプルすることstream_get_contents()は、おそらくあなたを殺しているものです。base64データ(通常は生のコンテンツの約33%)を保持する必要があるだけでなく、処理するcsvオーバーヘッドもあります。メモリに問題がある場合は、PHP内でgzipを実行するのではなく、コマンドラインのgzipアプリを呼び出すことを検討してください。

... database loop here ...
exec('gzip yourfile.csv');

また、行ごとに新しい配列を作成するのではなく、DBループ内で少しだけ最適化して、インプレースでエンコードすることもできます。

while($row = mysql_fetch_row($result)) {
   foreach ($row as $key => $val) {
       $row[$key] = base64_encode($val);
       fputcsv($fh, $row, chr(9));
   }
}

これによりメモリ使用量が大幅に削減されるわけではありません。データは1行しかないため、巨大なレコードフィールドを処理しない限り、あまり効果はありません。

于 2011-11-25T19:29:20.460 に答える
2

テストされていませんが、うまくいけばあなたは理解しています

function exportcsv($tables) {
    foreach ($tables as $k => $v) {
        $fh = fopen('compress.zlib://sql/' .$v. '.csv.gz', 'w');
        $sql = mysql_unbuffered_query("SELECT * FROM $v");
        while ($row = mysql_fetch_row($sql)) {
            fputcsv($fh, array_map('base64_encode', $row), chr(9));
        }
        fclose($fh);
        mysql_free_result($sql);
    }
}

関心のある編集ポイントは、mysql_unbuffered_queryの使用とphpの圧縮ストリームの使用です。通常のmysql_query()は、結果セット全体をメモリにバッファリングします。圧縮ストリームを使用すると、ファイルに書き込む前に、データを文字列としてphpメモリに再度バッファリングする必要がなくなります。

于 2011-11-25T19:38:43.953 に答える
1

そこにフラッシュを挿入することができます。現在、phpファイル全体がメモリに保持され、最後にフラッシュされますが、手動で行う場合は

fflush($fh);

また、ファイル全体をgzipで圧縮する代わりに、次を使用して1行ずつgzip圧縮することもできます。

$gz = gzopen ( $fh, 'w9' );
gzwrite ( $gz, $content );
gzclose ( $gz );

これにより、ファイル全体を作成してgzipするのではなく、行ごとにパックされたデータが書き込まれます。

于 2011-11-25T19:33:35.753 に答える
0

http://johnibanez.com/node/21でチャンクに圧縮するためのこの提案を見つけました

目的に合わせて変更するのは難しくないようです。

function gzcompressfile($source, $level = false){ 
    $dest = $source . '.gz'; 
    $mode = 'wb' . $level; 
    $error = false; 

    if ($fp_out = gzopen($dest, $mode)) { 
        if ($fp_in = fopen($source, 'rb')) { 
            while(!feof($fp_in)) {
                gzwrite($fp_out, fread($fp_in, 1024*512)); 
            }
            fclose($fp_in); 
        } 
        else
            $error=true; 

        gzclose($fp_out); 
    } 
    else 
        $error=true; 

    if ($error)
        return false; 
    else
        return $dest;
} 
于 2011-11-25T19:32:35.553 に答える