I am querying a database which has the following schema:
People
------
PersonId
PeopleTags
----------
PeopleId
TagId
Tags
----
TagId
Guid
A person may have multiple tags and when querying the requirement is to find people that have ALL of a set of mandatory tags and ANY of a set of optional tags.
At the moment, I'm doing a separate subquery per mandatory tag and a single subquery for the optional tags which gives me something like this:
SELECT People.*
FROM People
WHERE
PeopleId IN (SELECT PeopleId FROM PeopleTags WHERE TagId IN (SELECT TagId FROM Tags WHERE Guid = '83c55f3d...')
AND PeopleId IN (SELECT PeopleId FROM PeopleTags WHERE TagId IN (SELECT TagId FROM Tags WHERE Guid = '8159248a...')
AND PeopleId IN (SELECT PeopleId FROM PeopleTags WHERE TagId IN (SELECT TagId FROM Tags WHERE Guid IN ('737d9015...', 'b7a5974e...')
There can be any number of mandatory and optional tags and we occasionally get this error:
The query processor ran out of internal resources and could not produce a query plan. This is a rare event and only expected for extremely complex queries or queries that reference a very large number of tables or partitions. Please simplify the query. If you believe you have received this message in error, contact Customer Support Services for more information.
Researching this error suggests that it is due to sub queries with large IN lists (which is entirely possible with the code as it stands).
Is there a better way to write this query? I have tried joining to the table multiple times but it doesn't return any results if I do.
SELECT People.*
FROM People
INNER JOIN PeopleTags ON PeopleTags.PersonId = People.PersonId
INNER JOIN Tags t1 on t1.TagId = PeopleTags.TagId and t1.Guid = '8159248A...'
INNER JOIN Tags t2 on t2.TagId = PeopleTags.TagId and t2.Guid = '415DF7A3...'
I can change
PeopleId IN (SELECT PeopleId FROM PeopleTags WHERE TagId IN (SELECT TagId FROM Tags WHERE Guid = '83c55f3d...')
to
PeopleId IN (SELECT PeopleId FROM PeopleTags INNER JOIN Tags ON Tags.TagId = PeopleTags.TagId WHERE Guid = '83c55f3d...')
for each mandatory tag, will that make a difference?