5

を使用して、読み取って処理した行が破棄される破壊的なfgetcsv読み取りをどうにかして実行できますか?the script timed out

追加の詳細:

200 MB の .gz ファイルとして出くわすベンダーから毎日の製品フィードを取得しています。ファイルを解凍すると、約 500,000 行、20 ~ 25 フィールドの 1.5 GB の .csv になります。この情報を MySQL データベースに読み込む必要があります。理想的には PHP を使用して、CRON をスケジュールし、Web ホスティング プロバイダーでスクリプトを毎日実行できるようにします。

ホスティングプロバイダーによってサーバーのハードタイムアウトが180秒に設定されており、単一のスクリプトの最大メモリ使用制限は128mbです。これらの制限は私が変更することはできません。

私の考えは、fgetcsv 関数を使用して .csv から情報を取得することでしたが、3 分間のタイムアウトのためにファイルで複数のパスを取得する必要があると予想していました。前のパスですでに処理された行をスキップするサイクルを費やす必要がないように処理します。

4

3 に答える 3

5

Streamのように読むと、タイムアウトやメモリエラーをある程度回避できます。行ごとに読み取り、各行をデータベースに挿入します (またはそれに応じて処理します)。このようにして、反復ごとに 1 行だけがメモリに保持されます。巨大な csv ファイルを配列にロードしようとしないでください。実際に大量のメモリを消費します。

if(($handle = fopen("yourHugeCSV.csv", 'r')) !== false)
{
    // Get the first row (Header)
    $header = fgetcsv($handle);

    // loop through the file line-by-line
    while(($data = fgetcsv($handle)) !== false)
    {
        // Process Your Data
        unset($data);
    }
    fclose($handle);
}
于 2013-10-22T11:35:41.947 に答える
1

より良い解決策 (連続的に巻き戻し、開いているファイル ストリームに書き込むのは驚異的に非効率的です) は、読み取った各レコードのファイル位置を追跡し ( ftellを使用)、読み取ったデータと共に保存することだと思います。再開する必要があり、最後の位置まで fseek するだけです。

過去にこれに問題があり、独自のphpコードを書くことになりましたが、mysqlのファイル読み取り機能を使用してファイルを直接ロードすることもできます(これはおそらくはるかに高速です)。

ホスティングプロバイダーによってサーバーのハードタイムアウトが180秒に設定されており、単一のスクリプトの最大メモリ使用制限は128mbです。これらの制限は私が変更することはできません。

何を試しましたか?

メモリはphp.iniファイル以外の方法で制限できますが、実際に別の実行時間を使用できないようにする方法は想像できません(ini_setが無効になっている場合でも、コマンドラインからphp -dを実行できます) max_execution_time=3000 /your/script.php または php -c /path/to/custom/inifile /your/script.php )

データファイル全体をメモリに収めようとしている場合を除き、メモリ制限が 128Mb であっても問題はありません。

于 2013-10-22T12:49:07.883 に答える