Решил оптимизировать запрос.
Запрос вытаскивал посты из таблицы posts по некоторым условиями и сортировал их по дате или непрочитанности. Непрочитанность - это отсутствие постов в таблице post_user.
В итоге получался примерно такой код для сортировке по дате
select * from posts where ... order by created_at desc
и такой для сортировке по непрочитанности
select * from posts
left join post_user on post_user.post_id = posts.id and post_user.user_id = 2
where ...
order by post_user.id desc, posts.created_at desc
Второй запрос работает намного медленнее первого. Поэтому я решил отдельно выбрать все непрочитанные новости и отдельно все прочитанные. Просто склеить 2 результата не получится, потому что в запросах используется limit offset, поэтому я решил объединить 2 запроса в один с помощью union.
Получилось так:
(select 0 as is_unread, * from posts where ...)
union
(select 1 as is_unread, * from posts where ... and not exists(select * from post_user where post_id = posts.id and user_id = 2))
order by is_unread desc, created_at desc
limit 20 offset 0
Оба этих запроса по отдельности выполняются достаточно быстро и в explain все хорошо.
Но с использованием union значение поля rows увеличивается с 900 (если выполнять каждый запрос отдельно) до 200000. Дело не в сортировке, если выполнить запрос без сортировки, ничего не изменится, и даже если второй запрос в union будет полностью соответствовать первому, тоже ничего не изменится.
Почему так происходит?
И как бы вы сделали сортировку в таком случае?