Как и в вопросе по ссылке <a href="https://qna.habr.com/q/281973" rel="nofollow">Почему PostgreSQL использует неоптимальный план выполнения для простого запроса?</a>, я сталкиваюсь с аналогичной проблемой, но предложенное решение мне не помогло. У меня есть простая таблица, структура которой следующая: <br/> <pre><code>Table "public.friends_info"
Column | Type | Collation | Nullable | Default
-----------------+--------+-----------+----------+---------
user_id | bigint | | |
friend_id | bigint | | |
unix_time_check | bigint | | |
Indexes:
"friends_info_user_id_friend_id_key" UNIQUE CONSTRAINT, btree (user_id, friend_id)
"ix_friends_friend_id" btree (friend_id)
"ix_friends_user_id" btree (user_id)</code></pre> <br/> Я выполняю два одинаковых запроса, но PostgreSQL выбирает для них разные планы выполнения: <br/> <pre><code>EXPLAIN (ANALYZE,BUFFERS) SELECT * FROM friends_info LEFT JOIN i ON friends_info.friend_id = i.user_id WHERE friends_info.user_id = 1;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Gather (cost=1063.49..41700.28 rows=5465 width=644) (actual time=3.039..18.789 rows=88 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=447 read=1
-> Nested Loop Left Join (cost=63.49..40153.78 rows=2277 width=644) (actual time=0.657..2.055 rows=29 loops=3)
Buffers: shared hit=447 read=1
-> Parallel Bitmap Heap Scan on friends_info (cost=62.92..20715.73 rows=2277 width=24) (actual time=0.621..0.629 rows=29 loops=3)
Recheck
Проблема неэффективных планов выполнения в PostgreSQL может быть обусловлена несколькими факторами, даже для подобных запросов. Вот некоторые из наиболее вероятных причин: 1. **Статистика**: PostgreSQL использует статистику для оценки стоимости выполнения различных операций. Если статистика устарела или недостаточно точна (например, если в таблицах регулярно добавляются/удаляются записи), оптимизатор может выбрать неэффективный план. Регулярно обновляйте статистику с помощью команды `ANALYZE`. 2. **Выборка данных**: Различия в объемах данных, подходящих под фильтры в `WHERE`, могут влиять на выбор плана. Если в одной из таблиц данных больше, чем в другой, это может привести к разному поведению планов. 3. **Размеры таблиц и индексов**: Объем данных в таблицах и индексов может меняться, и это влияет на то, какой план будет более эффективным. Если одна из таблиц значительно увеличилась в размере, это может влиять на оптимизатор. 4. **Настройки конфигурации**: Параметры конфигурации PostgreSQL, такие как `work_mem`, `effective_cache_size`, `random_page_cost`, и другие, могут влиять на то, как оптимизатор выбирает планы. Возможно, стоит поэкспериментировать с их значениями. 5. **Типы соединений и фильтров**: Разные типы соединений (например, Nested Loop, Hash Join) могут быть выбраны в зависимости от конкретных условий запроса. Иногда последовательный выбор соединения может приводить к различным планам для схожих запросов. 6. **Параллелизм**: Если в запросе задействован параллелизм (как показано в вашем выводе плана с `Gather` и `Workers Planned`), различия в доступных ресурсах или текущей загрузке системы могут вызвать выбор различных планов. Чтобы лучше разобраться, вы можете сделать следующее: - Запустите `ANALYZE` для обеих таблиц после проверки или изменения данных. - Сравните статистику, используя `pg_stats` для ваших столбцов, чтобы увидеть, как различные параметры могут влиять на выбор плана. - Используйте `EXPLAIN (ANALYZE, BUFFERS)` для более глубокого анализа планов выполнения. - Поэкспериментируйте с настройками конфигурации, чтобы видеть, влияют ли они на выбор плана. Если после всех этих шагов проблема все еще остается, возможно, стоит обратиться к сообществу PostgreSQL или разработать временное решение, например, использовать подсказки `SET enable_*` для принудительного выбора определенных планов.
Я выполняю 2 одинаковых запроса
"WHERE friends_info.user_id = 1" vs "WHERE friends_info.friend_id= 1"
о да, одинаковые, да как бы не так. Полностью разные запросы, естественно, могут иметь различные оптимальные планы выполнения.
Bitmap Index Scan on ix_friends_user_id (cost=0.00..61.56 rows=5465 width=0) (actual time=0.742..0.743 rows=88 loops=1)
Суть ошибки выбора плана. Какое распределение данных в таблице? Каков размер самой таблицы? Вероятно несколько пользователей занимают значительную часть таблицы и это сбивает оценку селективности.
Простое чуть приподнять SET STATISTICS по полю, собрать новый analyze и посмотреть на оценку числа строк.
PS: индекс ix_friends_user_id должен быть удалён как бесполезный при наличии friends_info_user_id_friend_id_key