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

Как добиться баланса между скоростью и производительностью при импорте ~200к строк в базу данных?

Всем привет.

Вводные: есть база(MySQL), .csv-файл с ~200к строк (каждая строка по 10-15 символов примерно), нужно их дополнить данными и загнать в базу данных

Сейчас иду таким способом: обхожу все эти строки, формируя массив из 1-2к ORM моделей с дополнительными данными (типа какого-то name и тд), затем вставляю с помощью saveMany в базу, подчищаю массив и так до окончания строк. И в целом все ок, но не устраивает скорость импорта. Пошел ради интереса на крайности, начал формировать массив по 30к элементов и все равно скорость не особо отличается. Предполагаю, узкое горлышко как раз в стыке с базой. Массив из 30к быстро формируется, ~1 секунда. В базу же вставляется долго, около минуты (проверял на горячую, вставка идет понемножку, отсюда и лочится процесс, что в будущем может привести к падению скрипта, например)

Щас в идеях есть разве что вставкой через insert. На скорую руку попробовал, результат все равно не тот. Хотелось бы услышать кто что думает, у кого какие идеи в какую сторону копать. Возможно, здесь вообще подход стоит сменить?
  • Вопрос задан
  • 359 просмотров
Подписаться 1 Средний 6 комментариев
Решения вопроса 1
mayton2019
@mayton2019
Bigdata Engineer
1) 200k строк это вобщем-то мало для современных БД
2) Загрузи как есть в новую таблицу вот как тут пишут
https://stackoverflow.com/questions/14127529/impor...
3) С помощью alter add column добавь нужные колонки и обнови через UPDATE.

Никуда больше копать не надо. Загрузка данных - уже 30 лет как решенная коробочная задача.
И ее делают встроенные в БД утилиты и сама БД если если ей доступен диск с csv-файлом.

Никакой ORM тебе тоже не нужен. ORM вообще - противопоказан для задач аналитики и ETL.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
JhaoDa
@JhaoDa
LaravelRUS Team
Щас в идеях есть разве что вставкой через insert. На скорую руку попробовал, результат все равно не тот.
Как попробовал? Просто заменить сохранение модели на инсёрт или пачку записей одним инсёртом?

Вставку чанка (1-2к/30к/етц) записей пробовал завернуть в транзакцию? Если да и лучше не стало, то, может, БД не затюнена по настройкам. Или пора чанки в параллель обрабатывать/сохранять.
Ответ написан
iMedved2009
@iMedved2009
Не люблю людей
В данный конкретный вариант у вас похоже реализован самый медленный вариант вставки - а именно куча отдельных insert, с коммитом после каждой, ибо никакой магии в saveMany нету - в цикле обходим массив и по одному вставляем.

1. Использовать номальный bulk insert. Это вроде как делается просто
Model::insert([
  [row1], [row2], [row3], [row4], 
]);

тогда на выходе вы должны получить запрос вида insert into table() values(row1), (row2), (row3);

2. Обернуть в транзакцию как советовал JhaoDa . Это хуже чем первый вариант, но лучше вашего.
Ответ написан
Stalker_RED
@Stalker_RED
LOAD DATA... INFILE 'myfile.csv'...
https://dev.mysql.com/doc/refman/8.0/en/load-data.html
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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