Большой запрос в MySQL (php)

71
04 июля 2021, 11:50

Есть группа в ВКонтакте, я получаю список всех участников группы и записываю их идентификаторы в базу данных.

Сейчас код выглядит так:

$paramerts = http_build_query($arguments);
start:
$request = json_decode(file_get_contents("https://api.vk.com/method/groups.getMembers?$paramerts"));
$items = $request->response->items;
foreach ($items as $key => $value) {
    if ($key == 999) {
        $arguments['offset'] += 1000;
        $response[] = $value;
        goto start;
    } else {
        $response[] = $value;
    }
}
$sql = '';
foreach ($response as $user_id) {
    $sql .= '(' . $user_id . ',' . $group_id . '),';
}
$sql = substr($sql, 0, -1);
mysqli_query($connection, 'INSERT `group_members` (`user_id`, `group_id`) VALUES ' . $sql);

При добавлении группы с 100 000 участников, проблем нет. Но если эта группа с 1 000 000, то массив создаётся за 50 секунд а запрос в базу данных в итоге не выполняется. Но есть группы и с 10 000 000 участников.

В дальнейшем мне ещё придётся получать из БД список участников, сравнивать с новым список и обновлять его новыми участниками. Так я смогу узнать новых подписчиков группы. Примерно так работает приложение в ВКонтакте "Дезертир".

Как сделать обработку больших групп?

Answer 1

Для таких ресурсоемких операций есть типовое решение - выполнение задания в фоновом режиме. Т.е. Вы создаете некий код, который обрабатывается не как запрос браузера к вэб-серверу, а помещается в очередь заданий, а затем выполняется обработчиком в фоновом режиме. Самостоятельно "велосипедить" не рекомендую, как-то сам вынужден был частичную функциональность реализовать - умаялся. В качестве примера решения привожу ссылку на аналогичную функциональность, предоставляемую Laravel. Можно воспользоваться решениями от любых других фреймворков.

При этом такое большое задание, как обработка 10 млн записей, можно разбить на части и реализовать в виде нескольких заданий, каждое из которых обрабатывает свою часть общего объема. Код один и тот же, параметры для выполнения разные.

Update

Вы все значения вгоняете в одну строку. Для того же MySQL есть ограничение на максимальную длину запроса. Желательно грузить данные в базу порциями. Например, каждые 1000 (или 10 000) обработанных пользователей оформлять отдельным оператором SQL и инсертить. Если для Вас важна целостность данных - оформите всю операцию добавления данных в виде транзакции, и завершайте транзакцию после последнего инсерта. Тогда в случае сбоя в работе скрипта в базу не попадет ничего, а в случае успешного завершения - одномоментно появятся все загруженные записи.

READ ALSO
Функция для фильтрации массива

Функция для фильтрации массива

Есть ли такая встроенная функция в php, которая примет в аргументы набор ключей и отфильтрует массив, отбросив все значения которые не совпадают...

88
Роутинг не работает на хостинге. PHP

Роутинг не работает на хостинге. PHP

Ребят, прохожу курс ООП PHP у одного парняУчит писать блог на ООП

120
Парсить изображения партиями

Парсить изображения партиями

Доброго времени сутокДелаю парсинг изображений, дело в том что целевой сервер отдает только по 60 - 70 изображений

83
Composer локально

Composer локально

в локальной сети компании нет доступа в интернетВстал вопрос с Composer, можно ли настроить Composer, что бы он ходил в локальный репозиторий (в локальной...

118