У меня есть большой файл CSV, который мне нужно разбить на 4 части, а затем отправить данные в базу данных; проблема в том, что файл CSV может быть 1 ГБ + (и их может быть больше, чем один за раз), что создает различные временные задержки и проблемы с памятью.Разбор и обработка больших файлов
Мне нужна помощь в том, как я могу улучшить и ускорить процесс.
Файл, который я тестировал, содержит 45000 записей; ~ 10mb файл.
В настоящее время я загружаю файл в массив, который использует в 3 раза больше размера файла, поэтому для файла 10mb мы говорим о памяти 30 МБ; Я надеюсь уменьшить потребность в памяти 30 МБ, читая файл по строкам, но чтобы посмотреть на это.
Часть обработки довольно проста, по существу, я прохожу через массив данных.
Последняя часть хранит данные в базе данных, где основная проблема на данный момент находится, из-за времени, которое требуется для сохранения данных в базе данных;
Первоначально я попытался создать большую строку и отправить ее все в БД, но для записи 22k требуется около 2 ГБ памяти RAM; даже если этот процесс довольно быстрый, я все время теряю память.
Мой текущий метод, который я реализовал, добавляет строку за раз, что не требует много памяти, но для обработки записей 45k может потребоваться почти час.
Следующий шаг - посмотреть на создание файла mysql с полным списком запросов и импорт всего этого в MySQL с помощью функции импорта mysql.
Было бы замечательно, если бы кто-нибудь может посоветовать о том, как я могу улучшить производительность сценария дальнейшего ..
Update 1 Прямо сейчас я не загрузить файл в память больше, и файл построчно процесса по линии. Для обработки большого файла не требуется много времени. Для обработки файла данных 500 МБ требуется несколько секунд.
На импорт в БД сторону вещей у меня есть два метода в месте, которое я пытаюсь:
- Использование PDO, оператор импорта в то время: занимает около 1 минуты для обработки файла данных 5 Мб; очень медленно
- Использование mysql < file.sql, импорт выполняется быстрее, занимает около 1 минуты для обработки файла данных 10 МБ; который лучше, но все же медленный. Компромисс заключается в том, что мне нужно сгенерировать файл .sql, который может быть очень большим, в настоящий момент файл данных 20 МБ приведет к файлу .sql размером около 600 МБ;
На данный момент я рассматриваю попытку «LOAD DATA INFILE», но мне нужно выполнить работу из-за нескольких таблиц, имеющих отношение один к одному, и мне нужно иметь последний вставленный идентификатор.
Update 2
загрузки данных Local входной_файл удалось решенных некоторые проблемы жестких дисков; Мне также пришлось использовать SplFileObject, чтобы упростить чтение файлов.Файл, который я создаю для Load Data Local Infile, по-прежнему довольно большой, но он намного лучше, чем раньше.
На данный момент мне нужно выполнить цикл через файл и сохранить начальные/конечные точки, где находится информация, при этом я создаю все таблицы, кроме тех, которые нуждаются в внешних ключах. Итак, что я сделал:
Таблица A и таблица B имеют отношение один к большому: таблица A создается в первом цикле (цикл через файл), а кроме того, мы храним параметры для таблицы B в ячейке внутри Таблица А.
один второй цикл, мы петля через таблицу а и захватить данные из ячейки и создать новый набор строк в таблице В.
в первом цикле я имею для разбора параметров для таблицы B для улучшения производительности второго цикла.
У меня есть довольно много foreach/for операторов во втором цикле, из-за которых второй цикл занимает x4 как можно дольше.
Производительность на текущий момент следующим за 10MB файла:
- Первый цикл 6 секунд
- Второй контур 12 секунд
- Среднее Общее время 18-20 второго
Однако производительность как представляется, ухудшается по мере увеличения файла, 40 МБ файла:
- Первый цикл 30 секунд
- Второй контур 60 второй
- Среднее Общее время 90-100 секунд
Если я не параметры анализатора в первом цикле для выполнения Таблица B для 10Мб:
- Первый цикл 3 секунды
- Второй контур 16 секунд
- Средний балл: 19-22 секунда
Производительность для файла с 40 Мбайт велика в первом цикле, но ужасно во втором цикле.
Без каких-либо Foreach петель в первом и втором цикле потребуется около 3-4 секунд, чтобы обработать 10MB
Пример цикла Еогеасп в первом цикле, который организует параметры Таблица B:
public function parseRawParam($line, $titles) {
$params = [];
$line = str_replace("\n", "", $line);
$rows = explode(",", $line);
for($row_i = 4; $row_i < count($rows); $row_i++) {
if(strlen(trim($rows[$row_i])) < 1) {
break;
}
$params[$titles[$row_i]] = $rows[$row_i];
}
return $params;
}
$ линия может иметь параметры в любом месте от 4 и ДО 160.
Второго контура имеет цикл Еогеаспа, который обрабатывает вставку Params и это то, что занимает много времени:
public function insertParam($record_id, $params) {
$sql = "";
foreach ($params as $param => $value) {
$sql = '"' . $record_id . '","' . str_replace("'", "\'", trim($param)) . '","' . trim($value) . '";';
}
return $sql;
}
Я смотрел на производительность между различными версиями PHP, а PHP7 намного быстрее не сопоставлялся с php 5.6, поэтому я ищу обновить версии PHP и повысить производительность.
исследования LOAD DATA INFILE – e4c5
Попробуйте кусок его ...? Это компромисс в пространстве. Сколько места у вас есть или сколько времени вы готовы пожертвовать. 1 строка за запрос → очень медленная, 22 тыс. Строк на запрос → быстрая, но огромная потребность в памяти. Оптимальное решение → где-то между ними. – deceze