Че-то мне совсем разонравился постгрес.
Планировщик — ебаное говно, которое расчитано на работу неоптимизированных запросов в неоптимизированной базе, которая хотя бы большими кусками помещается в оперативную память. Короче говоря — в распиздяйском окружении. А в условии ограниченных ресурсов все плохо.
В итоге у меня на весь инстанс глобально стоит:
enable_bitmapscan = off
enable_hashjoin = off
enable_mergejoin = off
— просто чтобы избавиться от появляющихся зависших запросов, из-за которых пользователи отфутболиваются по таймауту.
Простой пример: изобретаем мы электронную почту.
Делаем таблицу messages (user_id, date, ...)
Делаем индекс для нее по (user_id, date DESC)
Каждому пользователю показываем 50 последних писем при помощи WHERE user_id = ... ORDER BY date DESC.
Ничего фантастического, самое обычное поведение самого обычного приложения.
Все работает очень быстро: делается index scan и nested loop 50 раз. Но только покудова мы одновременно не джоиним messages с какой-нибудь второстепенной хуетой. Тут планировщик начинает делать bitmap index scan, потом hash/merge join, а потом sort by date DESC. Беда в том, что писем у пользователя может быть 100 штук, а может быть 100 000 штук. Bitmap index scan в этом случае выбирает целый миллион, потом все это «быстро» и «эффективно» (как задумывалось планировщиком) джоинится, потом фильтруется лишнее (до 100 000 строк), потом сортируется, потом берутся верхние 50 писем. В результате пользователь со ста тысячами писем не может зайти в свой почтовый ящик вообще: он видит только nginx gateway timeout.
И ситуации подобные этой возникают постоянно. Иногда запрос работает хорошо, но только меняется аргумент в условии — все идет пиздой. Например, планировщик, которого попросили письма двухнедельной давности, может решить, что теперь-то эффективнее делать bitmap index scan — и все по-новой.
Обычная статистика не помогает, потому что, как я уже говорил, писем может быть и 100, и 100 000. Но в среднем — голубцы.
CREATE STATISTICS еще не опробовал. Надеюсь, конечно, что поможет, но едва ли это очевидное решение.
Хуй, блять, знает, какие исходники надо ковырять, чтобы сделать планировщик ПЕССИМЕСТИЧНЕЕ. Чтобы, блять, если в теории возможно, что план по выборке 50 обоссаных писем может закончится бедой — он не пользовался этим планом.
Хинтов в постгресе нет. Есть возможность отключать отдельные виды тактик на время сессии, и, по-моему, даже во время транзакции.
Вообще, все это хуйня, и через «еб твою мать!» с ней можно справиться. Но основной тренд очень расстраивает.
Быстро генерировать и фильтровать миллионы записей — основная задача любой базы данных, ничего удивительного, что именно это они и делают в обычном режиме, а ты злишься. Более того, даже LIMIT не обязан работать быстрее, чем полная выборка, — это всего лишь ожидаемая всеми оптимизация.
Думаю, тебе подойдёт решение с первой страницы поисковой системы: https://www.percona.com/blog/2007/04/06/using-delayed-join-to-optimize-count-and-limit-queries/