Задать вопрос

Как распараллелить парсинг и загрузку в БД на php?

Привет.
Есть пару файлов в CSV.
Размер файла около 2 гигабайт.

Залить нужно в БД (MySQL) где около 6 миллионов записей.

Я считываю значение, прогоняю по всей БД запись.
Если есть, обновляю на всякий случай данные, если нет - записываю в БД новую запись.

И вот этот процесс очень длителен.
Знаю, что php однопоточный. Но может будут идейки, как распараллелить.

Я вот думал, один скрипт считывает сколько строк в файле.
Делит на n-ое количество, например на 3.
Потом через exec запускаю php на выполнение,
считываю определенное количество строк, и работаю с ними.

В общем два медленных момента:
1. считывание файла, весь в ОЗУ не загнать
2. БД нужно не просто записать, а прогнать по всей БД, найти есть ли такая запись и после уже обовить или записать.
  • Вопрос задан
  • 822 просмотра
Подписаться 5 Средний 1 комментарий
Решения вопроса 5
Alex_Wells
@Alex_Wells
PHP/Kotlin
updateOrInsert несовместим с "собирать в ОЗУ". Он тупо делает select а потом insert.

Хз сколько это 2гб в записях. Если до нескольких миллионов - то тупо делаете пачками по 3-5 тыс. select, потом insert недубликатов такими же пачками по 3-5кж

Если больше - делаете тоже самое, но разбиваете файл на несколько и раздаете задачи джобам.
Ответ написан
Комментировать
DevMan
@DevMan
если это разовая (или не очень частая) задача вы больше времени потратите на распараллеливание, чем просто на импорт.

не нужно искать по всей базе, создайте уникальный индекс и воспользуйтесь odku или insert ignore (если уверены, что данные такие же).
да и csv - не единый набор данных, его спокойно можно читать построчно. набивать буфер и отправлять пачкой в бд.

в целом: если вам не нужно делать импорт каждые 5 минут, нет смысла ее параллелить.
Ответ написан
xmoonlight
@xmoonlight
https://sitecoder.blogspot.com
Если делать в один поток:
(Сначала, работаем БЕЗ базы)
1. Берём CSV и расставляем (формируя два новых файла рядом!) через консольный скрипт/программу в нём ID-шники согласно "таблице-связке" (которая тоже в файле хранится, её изначально надо будет сделать однократно): [ID в CSV] -> [ID в нашей базе]. Это может быть как артикул, так и название (или любой другой уникальный параметр для одной уникальной записи, включая хэширование).
Получаем CSV2-update (связанные записи) и CSV2-new (записи, которых нет в нашей БД).

(сортировка - по желанию, но она не нужна)

(Начинаем работать с базой)
2. Обновляем сначала те, что есть: CSV2-update
3. Затем, добавляем в БД новые позиции: CSV2-new.

4. После добавления - обновляем файл "таблицы-связок".

Итог:
1. Мы все "тяжёлые" операции делаем ВНЕ базы.
2. Мы ничего не ищем по базе, а сразу берём нужную запись по ID ("ключу").

Захотите сделать сразу всё и мультипоточно на PHP: pthreads в помощь!
Ответ написан
Комментировать
Mouvdy
@Mouvdy
Похожую задачу решил для себя иначе.

Поле в БД сделал уникальным по которому должна была идти проверка.

При импорте делаю только INSERT. В итоге данные или записываются или нет и можно распараллелить :)

1 млн записей на слабеньком сервере за +/- 1-3 минуты выполняется.
Ответ написан
Комментировать
@vitaly_il1
DevOps Consulting
2. БД нужно не просто записать, а прогнать по всей БД, найти есть ли такая запись и после уже обовить или записать.

Только это может быть медленным, читать файл не проблема.
Насколько медленно работает вставка? - активизируйте slow query log и посмотрите. С использованием индекса эта операция должна быть быстрой. Если нет - надо оптимизировать.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы