PHP/Yii2: как ускорить выполнение ~1 млн запросов подряд?

Всем привет.
Со стороннего сервера через API получается большой массив данных, который нужно раскидать по разным таблицам. Суммарно - миллион с чем-то записей. Нельзя, очевидно, пытаться решить вопрос "в лоб":
foreach ($array as $attributes) {
    $model = new Model();
    $model->setAttributes($attributes);
    $model->save();
}

Пробовал на меньших объемах, с ~200 000 записей сервер уже не справляется, а нынешний миллион - это только начало. Варианты думал такие:
1. Получение и запись по частям. Неудобно.
2. Запись всех данных в каждую таблицу одним запросом. Как? Транзакцией?

Может, есть что-нибудь еще?
  • Вопрос задан
  • 2982 просмотра
Пригласить эксперта
Ответы на вопрос 9
Taraflex
@Taraflex
Ищу работу. Контакты в профиле.
2. Запись всех данных в каждую таблицу одним запросом. Как? Транзакцией?

Голым mysqli без всяких оберток, пачками по столько вставок, сколько влезет максимум в . запрос (строка в 1мб должна влезать ),
Ответ написан
Комментировать
@PapaStifflera
Родился, вырос...
Используйте очереди.
Ответ написан
Комментировать
@ollisso
2 варианта я вижу:

1. LOAD DATA - выше уже дали ссылку.

2. insert сразу многих строк:

Пример:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

dev.mysql.com/doc/refman/5.6/en/insert.html

+ лучше всего тюнинг сервера, чтобы он был готов к таким объёмом (миллион строк - это ничего не говорит)

а как именно сервер не справляется ? (миллион строк - это ничего не говорит)
Ответ написан
Комментировать
@matperez
Можно еще слить все в файл, а потом импортировать через консоль.
Ответ написан
Комментировать
miraage
@miraage
Старый прогер
1) www.yiiframework.com/doc-2.0/yii-db-command.html#b...
2) Я видел такой приём

file_put_contents(
    '/path/to/some/insert/file.sql', // куда
    'INSERT INTO table VALUES', // формируем запрос вставки с экранированными данными
    FILE_APPEND // константа, которая указывает, что добавляем в конец файла
)


Затем, в консольке запускали такую команду:
tail -f /path/to/some/insert/file.sql | mysql -uUSER -pPASS DATABASE


Что мы получаем: скрипт добавляет инсерт запросы, tail -f каждую новую строчку передает напрямую на вставку в mysql
Ответ написан
Комментировать
He11ion
@He11ion
PHP-monkey
https://dev.mysql.com/doc/refman/5.6/en/load-data.html
Стандартный способ загрузки больших объемов.

"Сервер не справляется" - скорее всего памяти не хватает, разбивайте на куски, влезающие в память/выделяйте больше ее если так необходимо через Yii
Ответ написан
Комментировать
Marcuzy
@Marcuzy
php разработчик
Предлагаю вот такую простоую реализацию буфера, который каждые n строк пакетно записывает в БД: https://gist.github.com/marcuzy/3bff7ab350ac6741def0
Ответ написан
Комментировать
@movetz
Была схожая проблема на окружении с очень слабым сервером, боролись так - собирали все один текстовый, а потом через LOAD DATA все загружали. Было еще более костыльное решение через CSV файл и exec.
Ответ написан
Комментировать
@asd111
Разбей базу на части, части положи на разные сервера. Т.е. проведи шардинг или другими словами горизонтальное масштабирование.

Если данные не особо критичные можно попробовать перейти на memcache.

Слайды на тему. www.slideshare.net/profyclub_ru/web-20-c-9951602
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы