Обработка очень большого файла CSV без тайм-аута и ошибки памяти - PullRequest
24 голосов
/ 06 сентября 2011

В данный момент я пишу скрипт импорта для очень большого CSV-файла.В большинстве случаев проблема заключается в том, что он останавливается через некоторое время из-за тайм-аута или выдает ошибку памяти.

Моя идея заключалась в том, чтобы теперь анализировать файл CSV с шагом «100 строк», а после 100 строк автоматически вызывать скрипт,Я попытался добиться этого с помощью заголовка (местоположение ...) и передать текущую строку с помощью get, но это не сработало, как я хочу.

Есть ли лучший способ сделать это или у кого-то естьидея как избавиться от ошибки памяти и тайм-аута?

Ответы [ 5 ]

51 голосов
/ 06 сентября 2011

Я использовал fgetcsv для чтения CSV размером 120 МБ в потоковом режиме (это правильный английский?). Это читается построчно, а затем я вставляю каждую строку в базу данных. Таким образом, в каждой итерации в памяти сохраняется только одна строка. Сценарию еще понадобилось 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);
}
16 голосов
/ 14 августа 2012

Я считаю, что загрузка файла и вставка с использованием запроса LOAD DATA LOCAL mysql - быстрое решение, например:

    $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);
13 голосов
/ 06 сентября 2011

Если вас не волнует, сколько времени это займет и сколько памяти нужно, вы можете просто увеличить значения для этого скрипта.Просто добавьте следующие строки в начало вашего скрипта:

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

С помощью функции memory_get_usage () вы можете узнать, сколько памяти требуется вашему скрипту, чтобы найти хорошее значение дляmemory_limit.

Возможно, вы также захотите взглянуть на fgets () , которая позволяет читать файл построчно.Я не уверен, что это займет меньше памяти, но я действительно думаю, что это сработает.Но даже в этом случае вам нужно увеличить max_execution_time до более высокого значения.

1 голос
/ 24 мая 2018

Кажется, есть огромная разница между fgetcsv () и fgets (), когда дело доходит до потребления памяти.Простой CSV с одним столбцом превысил мой предел памяти в 512 МБ на 50000 записей с помощью fgetcsv () и потребовал 8 минут, чтобы сообщить об этом.

С помощью fgets () для успешной обработки 649175 записей потребовалось всего 3 минуты, имой локальный сервер даже не задыхался для дополнительного воздуха ..

Поэтому я советую использовать fgets (), если количество столбцов в вашем csv ограничено.В моем случае fgets () возвращал непосредственно строку в столбце 1. Для более чем одного столбца вы можете использовать explode () в одноразовом массиве, который вы отменяете () после каждой операции записи.Отброшенный ответ 3 @ ndkauboy

0 голосов
/ 06 сентября 2011

О.Просто сделайте этот скрипт с именем CLI, а не через глупый веб-интерфейс.Таким образом, никакое ограничение по времени выполнения не повлияет на это.
И не сохраняйте проанализированные результаты вечно, а записывайте их немедленно - так что на вас также не повлияет ограничение памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...