На данный момент я пишу сценарий импорта для очень большого CSV-файла. Проблема в том, что большинство раз она останавливается через некоторое время из-за тайм-аута или выдает ошибку памяти.
Моя идея теперь анализировала CSV-файл в шагах «100 строк» и после того, как 100 строк автоматически вернули сценарий. Я попытался достичь этого с помощью заголовка (location …) и передать текущую строку с помощью get, но это не сработало, как я хочу.
Есть ли лучший способ этого или кто-то имеет идею, как избавиться от ошибки памяти и таймаута?
Я использовал fgetcsv
для чтения 120 МБ csv потоковым способом (это правильный английский?). Это читается по строкам, а затем я вставлял каждую строку в базу данных. Таким образом, на каждой итерации сохраняется память в одной строке. Сценарий все еще нуждался в 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); }
с// 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); }
Если вам не важно, сколько времени потребуется и сколько памяти ему нужно, вы можете просто увеличить значения для этого скрипта. Просто добавьте следующие строки в начало скрипта:
ini_set('memory_limit', '512M'); ini_set('max_execution_time', '180');
С помощью функции memory_get_usage () вы можете узнать, сколько памяти вашему скрипту нужно найти для значения memory_limit.
Вы также можете взглянуть на fgets (), который позволяет вам читать файл по строкам. Я не уверен, что это занимает меньше памяти, но я действительно думаю, что это сработает. Но даже в этом случае вам нужно увеличить max_execution_time до более высокого значения.
Я считаю, что загрузка файла и вставка с использованием запроса 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);
Ой. Просто сделайте этот скрипт под названием CLI, а не через глупый веб-интерфейс. Таким образом, на это не повлияет лимит времени исполнения.
И не сохраняйте анализируемые результаты навсегда, но немедленно их записывайте – так что вы также не будете затронуты лимитом памяти.