現時点では、非常に大きなCSVファイルのインポートスクリプトを作成しています。問題は、タイムアウトのためにしばらくしてから停止するか、メモリエラーをスローする場合がほとんどです。
私のアイデアは、CSVファイルを「100行」の手順で解析し、100行後にスクリプトを自動的に呼び出すことでした。私はヘッダーでこれを達成しようとしました(場所...)、getで現在の行を渡しましたが、それは私が望むようにはうまくいきませんでした。
これに良い方法はありますか、誰かがメモリエラーとタイムアウトを取り除く方法を知っていますか?
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);
}
ファイルをアップロードし、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);
所要時間と必要なメモリ量を気にしない場合は、このスクリプトの値を単純に増やすことができます。スクリプトの先頭に次の行を追加するだけです。
ini_set('memory_limit', '512M');
ini_set('max_execution_time', '180');
関数 memory_get_usage() を使用すると、スクリプトがmemory_limitの適切な値を見つけるために必要なメモリ量を確認できます。
fgets() を見て、ファイルを1行ずつ読み取ることもできます。それがより少ないメモリを必要とするかどうかはわかりませんが、これはうまくいくと本当に思います。ただし、この場合でも、max_execution_timeをより高い値に増やす必要があります。
メモリ消費に関しては、fgetcsv()とfgets()には大きな違いがあるようです。 1列のみの単純なCSVは、fgetcsv()を使用して50000レコードの512Mのメモリ制限を超え、それを報告するのに8分かかりました。
Fgets()を使用すると、649175レコードを正常に処理するのに3分しかかからず、ローカルサーバーは追加の空気を切らしていませんでした。
したがって、csvの列数が制限されている場合は、fgets()を使用することをお勧めします。私の場合、fgets()は列1内の文字列を直接返しました。複数の列については、各レコード操作の後にunset()する使い捨て配列でexplode()を使用できます。回答3を親指しました@ndkauboy