Парсинг и запись большого CSV
Задача следующая - имеется большой CSV-файл, откуда берётся - не известно, но подозреваю, что выгрузка из 1с, и скормить его в sql-базу, далее выводить из него данные плагином WP. На текущий момент его размер чуть больше 2гб.
Сам файл разобрать не проблема, проблема встаёт в том, что стандартными средствами PHP это всё происходит а) долго, б) жрёт много памяти. Суммарно там чуть больше 3 миллионов строк.
Собственно, хотелось бы получить советов, как это дело лучше оптимизировать, что бы в один момент не уронить сайт на неопределенное время?
Ответы (1 шт):
Для оптимизации по памяти можно читать файл построчно и сохранять в базу каждую строку(или накапливая по 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 или поискать аналоги для вашего сервера БД