Cóż, dla każdego wiersza w „grupach” postgresql wykonuje pełne skanowanie kategorii products_categories, co nie jest dobre. Niekoniecznie jest to problem z konfiguracją, ale być może zapytanie można sformułować bez zagnieżdżania takich podzapytań?
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
Również products_categories
mieć indeks na product_id
?