Как ускорить миграцию данных между Битрикс24 и другим сервисом? Случай из нашей практики
Миграция данных между разными сервисами это всегда сложный процесс. Мы разрабатываем и поддерживаем большое количество интеграций для Битрикс24 и часто сталкиваемся с подводными камнями и нештатными ситуациями, для которых приходится искать решение. Одна из самых распространенных проблем — очень медленный перенос данных или полное зависание импорта. Об одном из таких случаев мы сейчас и расскажем.
Итак, клиент столкнулся с проблемой — миграция зависла на стадии импорта активити и за сутки успевала добавить в таблицу в лучшем случае 500 записей. Расширенное логирование что, что во всём виноват вот этот участок кода:
$entity = Pipedrive\ActivitiesTable::getRow([ 'filter' => [ 'MEMBER_ID' => $this->memberId, 'PIPEDRIVE_ID' => $row['id'], ], 'select' => ['ID'] ]);
На его выполнение уходило чудовищное количество времени - около пяти минут. Уточнение параметров таблицы показало, что в ней отсутствует индексирование, и выборка полей по фильтру совершалась простым перебором всех записей от первой до последней, а было их там два с половиной миллиона.
Таким образом, решение проблемы оказалось простым - единовременной индексацией таблицы SQL-командой:
CREATE INDEX activity_pipedrive_memid_pipid_x ON bx24_activities_pipedrive(MEMBER_ID, PIPEDRIVE_ID)
Важно: порядок индексации должен совпадать с порядком полей в фильтре метода getRow(). Так же перед индексацией необходимо отключить крон для текущего приложения и остановить php-процесс:
Открыть в консоли cron на редактирование командой: sudo crontab -e -u bitrix Посмотреть процессы на сервере: ps aux | grep php Убить процесс: sudo kill -9 число_из_второй_колонки_предыдущего_вывода
Во время индексации (для таблицы весом в 3.5Gb оно, как показала практика, составляет порядка пяти минут) нельзя закрывать консоль SQL-запроса, пока не появится подтверждение об успешной операции.
После этого время запроса getRow() сократилось с пяти минут до миллисекунд, а один тик крона стал выполняться минут за десять против суток до индексации. Правда, слегка подросло время на добавление и обновление записей, поскольку на индексацию тоже тратится определённое время, но оно настолько мало, что им можно пренебречь.
Вывод — при создании миграторов необходимо индексировать таблицы по тем полям, которые используются в методе getRow() и аналогичных, у которых фильтрация происходит не по первичному ключу.