Парсинг и запись большого CSV

Задача следующая - имеется большой CSV-файл, откуда берётся - не известно, но подозреваю, что выгрузка из 1с, и скормить его в sql-базу, далее выводить из него данные плагином WP. На текущий момент его размер чуть больше 2гб.

Сам файл разобрать не проблема, проблема встаёт в том, что стандартными средствами PHP это всё происходит а) долго, б) жрёт много памяти. Суммарно там чуть больше 3 миллионов строк.

Собственно, хотелось бы получить советов, как это дело лучше оптимизировать, что бы в один момент не уронить сайт на неопределенное время?


Ответы (1 шт):

Автор решения: UrfinJuezz

Для оптимизации по памяти можно читать файл построчно и сохранять в базу каждую строку(или накапливая по 10/50/100 строк)

<?php

class CSVStreamReader
{
    /** @var resource */
    private $file;
    private string $separator;
    private string $enclosure;
    private string $escape;

    /**
     * @param resource $file
     * @param string $separator
     * @param string $enclosure
     * @param string $escape
     */
    public function __construct($file, string $separator = ",", string $enclosure = '"', string $escape = '\\')
    {
        $this->file = $file;
        $this->separator = $separator;
        $this->enclosure = $enclosure;
        $this->escape = $escape;
    }

    public function read(): Generator
    {
        while (false !== $row = fgets($this->file)) {
            yield str_getcsv($row, $this->separator, $this->enclosure, $this->escape);
        }
    }
}

$file = fopen('file.csv', 'rb');
$reader = new CSVStreamReader($file);
foreach ($reader->read() as $row) {
    //TODO save to DB, or make something useful
    print_r($row);
}

Не думаю что это сильно спасёт по времени, но тут можно посмотреть в сторону асинхронной обработки. То есть загружаем файл из админки, говорим пользователю что файл загружен и обрабатывается, запускаем отдельным процессом обработку файла, а пользователю показываем прогресс, и по итогу результат обработки.

альтернатива: Если вы уверены в данных и не боитесь их загружать без валидации, то можно посмотреть в сторону https://dev.mysql.com/doc/refman/8.0/en/load-data.html или поискать аналоги для вашего сервера БД

→ Ссылка