I would like to know whether multiple similar exists conditions can be combined in a meaningful and performant way.
Let us assume the following example: Different activities can be assigned to a service (n-m). Activities can be grouped independently into activity groups. Activity groups can be assigned to a group type.
If I now want to find all services that have a reference to certain group types and I want to link the condition by OR, then this is relatively simple by combining EXISTS and IN.
select *
from service
where exists (
select 1
from activitiy
join activitiy_activitiy_group
on activitiy.id = activitiy_activitiy_group.id_activitiy
join activitiy_group
on activitiy_activitiy_group.id_activitiy_group = activitiy_group.id
where (
activitiy_group.id_type in (1, 3)
and activitiy.id_service = service.id
);
If, on the other hand, I want to link the condition by AND, then it is not quite so simple. I could add multiple EXITS conditions:
select *
from service
where exists (
select 1
from activitiy
join activitiy_activitiy_group
on activitiy.id = activitiy_activitiy_group.id_activitiy
join activitiy_group
on activitiy_activitiy_group.id_activitiy_group = activitiy_group.id
where (
activitiy_group.id_type = 1
and activitiy.id_service = service.id
)
and
exists (
select 1
from activitiy
join activitiy_activitiy_group
on activitiy.id = activitiy_activitiy_group.id_activitiy
join activitiy_group
on activitiy_activitiy_group.id_activitiy_group = activitiy_group.id
where (
activitiy_group.id_type = 3
and activitiy.id_service = service.id
);
But I wonder if this approach is performant for many filter elements. I experimented a bit and one approach would be with only one subselect, by selecting all distinct activity group type ids related to a service into one array and comparing it with the filter values:
select *
from service
where true =
(select ARRAY_AGG(activitiy_group.id_type) @> ('{1,3}'::Integer[])
from activitiy
join activitiy_activitiy_group
on activitiy.id = activitiy_activitiy_group.id_activitiy
join activitiy_group
on activitiy_activitiy_group.id_activitiy_group = activitiy_group.id
where ativitiy.id_service = service.id);
But here, too, the question arises as to whether this is really performant. Can anyone assess this, or is there perhaps a more sensible alternative approach? I assumed that the underlying basic problem is a standard problem, but unfortunately could not find any other approach on the internet.
ANDcase burns down to a relational-division problem. See: stackoverflow.com/a/7774879/939860 "... whether this is really performant" - The best solution always depends on the actual, relevant environment. We need the range of possible input, what's rare and what's common, cardinalities, table definitions, Postgres version, ... Follow instructions given here: stackoverflow.com/tags/postgresql-performance/info