Комментарии 2
В декартовом произведение, условие m.chat_id IN (SELECT ch.id FROM chats ch WHERE ch.telegram_chat_id = b.telegram_chat_id) внутри JOIN messages m приводит к катастрофическому падению производительности (subquery unnesting failure в MySQL 8 для внешних зависимостей в IN), из-за чего запрос на продакшене с 75 RPS гарантированно уходёт в Lock Wait Timeout или вечный Scan.
Здесь, кажется, стоит разделить две проблемы. Ошибка в расчёте видна из самого SQL: base уже содержит строку на каждое сообщение, а второй JOIN messages повторно присоединяет все сообщения пользователя без привязки к конкретному персонажу. В результате строки размножаются и метрика искажается.
А вот гарантированный subquery unnesting failure и последующий Lock Wait Timeout из текста запроса уже не следуют. MySQL 8 может преобразовать такой IN в semijoin, поэтому без EXPLAIN и информации об индексах нельзя уверенно сказать, какой план был выбран и где именно возникло узкое место.
Сохранился ли план выполнения исходного запроса? Было б интересно сравнить его с исправленной версией.

1.5 миллиона событий в день и ни одной таблицы events: как мы считали продуктовую аналитику 300K-бота по голому проду