При работе с локальным контейнером, в который я импортировал данные из форума SMF2 с 20+ годами активности, я столкнулся с критической ошибкой в методе Topic.reset_all_highest.
После импорта данных в моей базе данных отображается около 60 тысяч обычных тем и примерно 400 тысяч тем типа private_message. Запросы в Topic.reset_all_highest вызывают геометрический рост количества строк, из-за чего диск переполняется (при начальном свободном пространстве в 120 ГБ).
В настоящее время я пытаюсь разбить запросы на управляемые части и выполнять их напрямую в Postgres, но это, конечно, неоптимально (к тому же я не уверен, что это вообще работает и даёт корректные результаты).
Я попытался найти, сталкивался ли кто-то ещё с подобной проблемой, но ничего не нашёл, поэтому задаюсь вопросом: не может ли это быть связано с моей собственной настройкой? Для справки: я использую последнюю версию Docker.
Недавно я выполнил импорт небольшого объёма данных, который, похоже, бесконечно завис на Topic.reset_all_highest, и мне пришлось прервать запрос в Postgres, чтобы продолжить работу. Раньше у меня не возникало такой проблемы, и я думал, что, возможно, мой сервер Postgres был перегружен (к нему подключено несколько сайтов).
Следующим шагом я планировал перейти на другой сервер Postgres, но пока ещё не успел этого сделать.
После того как первые два этапа моего эксперимента с «разделённым запросом» прошли успешно (X и Y для публичных тем), я попробовал третий (Z), и система зависла — то есть, согласно активности PostgreSQL, запрос был активен, а утилита top показывала, что процесс потребляет 100% ресурсов.
Тогда я снова посмотрел на SQL-запрос и нашёл проблему: оба запроса заканчиваются следующим образом
WHERE
topics.archetype <> 'private_message' AND
X.topic_id = topics.id AND
Y.topic_id = topics.id AND
(
topics.highest_staff_post_number <> X.highest_post_number OR
topics.highest_post_number <> Y.highest_post_number OR
topics.last_posted_at <> Y.last_posted_at OR
topics.posts_count <> Y.posts_count OR
topics.word_count <> Z.word_count
)
(в другом случае, разумеется, в качестве архетипа указан ‘private_message’).
Это означает, что в запросе отсутствует условие Z.topic_id = topics.id, что и вызывает экспоненциальный рост нагрузки.
Изменение условия WHERE в запросах на
WHERE
topics.archetype <> 'private_message' AND
X.topic_id = topics.id AND
Y.topic_id = topics.id AND
Z.topic_id = topics.id AND
(
topics.highest_staff_post_number <> X.highest_post_number OR
topics.highest_post_number <> Y.highest_post_number OR
topics.last_posted_at <> Y.last_posted_at OR
topics.posts_count <> Y.posts_count OR
topics.word_count <> Z.word_count
)
решило проблему для меня.
Стоит ли мне открыть PR?
Думаю, да. Если вы сможете найти коммит, который это сломал, это будет ещё более убедительно.
Я открыл PR по этому вопросу, хотя с некоторыми неприятными ограничениями (например, я не представляю, как протестировать это изменение).
Это изменение выглядит правильным, сливаю его.
(С точки зрения тестирования должно быть покрытие, и простого теста будет достаточно для проверки, нам просто нужно убедиться, что регрессии нет)