Это выделенный сервер со следующими характеристиками:
AMD Ryzen 7 3800X
64 ГБ ECC ОЗУ @ 2666 МГц
2 × 1,2 ТБ Intel P3600 NVMe SSD (ZFS RAID 1)
Виртуальной машине, на которой запущен Discourse, выделено 8 ядер процессора и 32 ГБ ОЗУ.
Полагаю, я обнаружил проблему с первым запросом, или, по крайней мере, способ подсказать планировщику запросов принять правильное решение. Вот запрос, который не завершался более 16 часов (это для значка «Первая цитата»):
SELECT ub.id
FROM user_badges ub
LEFT JOIN (
SELECT ids.user_id, q.post_id, p3.created_at granted_at
FROM
(
SELECT p1.user_id, MIN(q1.id) id
FROM quoted_posts q1
JOIN badge_posts p1 ON p1.id = q1.post_id
JOIN badge_posts p2 ON p2.id = q1.quoted_post_id
WHERE (TRUE OR ( p1.id IN (-1) ))
GROUP BY p1.user_id
) ids
JOIN quoted_posts q ON q.id = ids.id
JOIN badge_posts p3 ON q.post_id = p3.id
) q ON q.user_id = ub.user_id
AND (q.post_id = ub.post_id OR NOT TRUE)
WHERE ub.badge_id = 15 AND q.user_id IS NULL
Если добавить одну строку ORDER BY в правильное место, этот запрос теперь выполняется за несколько секунд:
SELECT ub.id
FROM user_badges ub
LEFT JOIN (
SELECT ids.user_id, q.post_id, p3.created_at granted_at
FROM
(
SELECT p1.user_id, MIN(q1.id) id
FROM quoted_posts q1
JOIN badge_posts p1 ON p1.id = q1.post_id
JOIN badge_posts p2 ON p2.id = q1.quoted_post_id
WHERE (TRUE OR ( p1.id IN (-1) ))
GROUP BY p1.user_id
) ids
JOIN quoted_posts q ON q.id = ids.id
JOIN badge_posts p3 ON q.post_id = p3.id
ORDER BY ids.user_id
) q ON q.user_id = ub.user_id
AND (q.post_id = ub.post_id OR NOT TRUE)
WHERE ub.badge_id = 15 AND q.user_id IS NULL
Кажется, система должна быть достаточно умной, чтобы сама выполнить эту сортировку в нужном месте, но, похоже, это не так… Тем не менее, исправление на данном этапе выглядит довольно простым.
Пока ещё не начал разбираться с другим запросом, касающимся percent_rank.