2011-09-06 21 views
19

非常に大きなCSVファイルのインポートスクリプトを作成しています。問題はタイムアウトのためにしばらくしてから停止するか、メモリエラーが発生することがほとんどです。非常に大きなcsvファイルをタイムアウトとメモリエラーなしで処理する

私の考えは、 "100行"ステップでCSVファイルを解析し、100行がスクリプトを自動的に呼び出すようになりました。私はヘッダー(位置...)でこれを達成しようとし、取得すると現在の行を渡すが、私がしたいようにうまくいかなかった。

もっと良い方法がありますか、誰かがメモリエラーとタイムアウトを取り除く方法を知っていますか?

+2

をあなたのCSVはどのように大きなファイルのか?これをデータベースにインポートする必要がありますか? –

+0

いくつかの比較も含まれている私の答えをhttp://stackoverflow.com/a/22744300/2037323でチェックしてください。 –

答えて

44

私はfgetcsvを使用してストリーム単位で120MBのcsvを読みました(正しい英語ですか?)。それは行ごとに読み込まれ、私はデータベースにすべての行を挿入しました。そうすれば、各繰り返しで1行だけがメモリに保持されます。スクリプトはまだ20分必要でした。走る。たぶん私は次回にPythonを試してみるだろう...巨大なcsvファイルを配列にロードしようとしないでください。本当にたくさんのメモリを消費します。

// WDI_GDF_Data.csv (120.4MB) are the World Bank collection of development indicators: 
// http://data.worldbank.org/data-catalog/world-development-indicators 
if(($handle = fopen('WDI_GDF_Data.csv', 'r')) !== false) 
{ 
    // get the first row, which contains the column-titles (if necessary) 
    $header = fgetcsv($handle); 

    // loop through the file line-by-line 
    while(($data = fgetcsv($handle)) !== false) 
    { 
     // resort/rewrite data and insert into DB here 
     // try to use conditions sparingly here, as those will cause slow-performance 

     // I don't know if this is really necessary, but it couldn't harm; 
     // see also: http://php.net/manual/en/features.gc.php 
     unset($data); 
    } 
    fclose($handle); 
} 
12

時間がかかり、必要なメモリ量が気にかからない場合は、このスクリプトの値を増やすだけです。あなたのスクリプトは、memory_limitのために良い値を見つける必要があるどのくらいのメモリを見つけることができますmemory_get_usage()機能で

ini_set('memory_limit', '512M'); 
ini_set('max_execution_time', '180'); 

:ちょうどあなたのスクリプトの先頭に次の行を追加します。

fgets()を見ると、1行ずつファイルを読むことができます。メモリが少なくて済むかどうかはわかりませんが、実際にはこれはうまくいくと思います。しかし、この場合でも、max_execution_timeを高い値に増やす必要があります。

+1

これはもちろん、ファイルが常に同じサイズであることがわかっている場合は、良いアプローチです。 –

+3

大きめの大きさでないことが分かっている場合は、それも機能します。 – 2ndkauboy

-2

ああ。愚かなWebインターフェイスではなく、このスクリプトをCLIと呼んでください。したがって、実行時間制限は影響を与えません。
解析結果は永遠に保存しないでください。ただちに書き留めてください。そのため、メモリ制限の影響を受けることはありません。

12

私は、例えば高速なソリューションを、ファイルをアップロードするとMySQLのLOAD DATA LOCALのクエリを使用して挿入見つける:

$sql = "LOAD DATA LOCAL INFILE '/path/to/file.csv' 
     REPLACE INTO TABLE table_name FIELDS TERMINATED BY ',' 
     ENCLOSED BY '\"' LINES TERMINATED BY '\r\n' IGNORE 1 LINES"; 
    $result = $mysqli->query($sql); 
+0

私は5分から+ 64000レコードのCSVを5秒以下にインポートしました。これは素晴らしいです! – Iznogood

関連する問題