PostgreSQL: существует против левого присоединения
-
29-09-2019 - |
Вопрос
Я много раз слышал, что postgres обрабатывает существуют Запросы даже быстрее тогда левое присоединение. http://archives.postgresql.org/pgsql-permance/2002-12/msg00185.php.
Это определенно верно для одной агрегации стола.
Но в нашем случае их больше, чем один и тот же запрос строит с существуют Что делает Postgres вешать навсегда:
explain
SELECT count(DISTINCT "groups".id) AS count_all
FROM "groups"
WHERE (exists(
select * from products p where groups.id = p.group_id AND exists(
select * from products_categories pc where p.id = pc.product_id AND pc.category_id in (2,3))) AND groups.id != 3)
результат:
Aggregate (cost=26413436.66..26413436.67 rows=1 width=4)
-> Seq Scan on groups (cost=0.00..26413403.84 rows=13126 width=4)
Filter: ((id <> 3) AND (subplan))
SubPlan
-> Index Scan using index_products_on_group_id on products p (cost=0.00..1006.13 rows=1 width=1483)
Index Cond: ($1 = group_id)
Filter: (subplan)
SubPlan
-> Seq Scan on products_categories pc (cost=0.00..498.49 rows=1 width=8)
Filter: ((category_id = ANY ('{2,3}'::integer[])) AND ($0 = product_id))
Это основная причина невероятно длительного исполнения? Это какой-то проблема конфигурации?
Спасибо, Богдан.
Решение
Ну, для каждого ряда в «группах» PostgreSQL выполняет полное сканирование продуктов_Категорий, что не хорошо. Не обязательно проблема конфигурации, но, возможно, запрос может быть указан, не вложенные в таковые подзаимники?
SELECT count(DISTINCT "groups".id) AS count_all
FROM "groups"
WHERE exists(
select 1 from products p where groups.id = p.group_id
join products_categories pc on pc.product_id = p.id
where pc.category_id in (2,3)
) and groups.id <> 3
Также делает products_categories
иметь индекс на product_id
?