The problem query uses multiple Intersect.
Changing it to an in ('alpha','beta','gamma','delta','epsilon','phi') group by having count() = 6 is not an option as the application supports like with wild cards (e.g. alpha%). But the count() = 6 query runs in less than 1 second.
With wild card could use multiple joins and that is how it used to be structured. At 4 or less an Intersect performs better than the multiple joins but unfortunately did not test at 5 or more.
Query performs great with any 4 terms - less than 1 second.
Literally any 4 - first 4, last 4, or middle 4.
On 5 or more then it dies - I killed the query at 2 minutes.
At 6 terms let it run - 5 minutes returning 795 rows.
Up to 4 terms the query plan mixes loop with merge joins.
At 5 or more terms the query plan is all loop joins.
Is there syntax for applying query hints to an Intersect?
Tried two sets of 3 using () () but that did not change the query plan.
( -- start term
select [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
where [ftsIndexWordOnce].[wordID] in (
select [id] from [FTSwordDef] with (nolock)
where [word] like 'alpha')
) -- end term
INTERSECT
( -- start term
select [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
where [ftsIndexWordOnce].[wordID] in (
select [id] from [FTSwordDef] with (nolock)
where [word] like 'beta')
) -- end term
INTERSECT
( -- start term
select [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
where [ftsIndexWordOnce].[wordID] in (
select [id] from [FTSwordDef] with (nolock)
where [word] like 'gamma')
) -- end term
INTERSECT
( -- start term
select [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
where [ftsIndexWordOnce].[wordID] in (
select [id] from [FTSwordDef] with (nolock)
where [word] like 'delta')
) -- end term
INTERSECT
( -- start term
select [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
where [ftsIndexWordOnce].[wordID] in (
select [id] from [FTSwordDef] with (nolock)
where [word] like 'epsilon')
) -- end term
INTERSECT
( -- start term
select [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
where [ftsIndexWordOnce].[wordID] in (
select [id] from [FTSwordDef] with (nolock)
where [word] like 'phi')
) -- end term
Think I have a fix
select distinct [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
Inner Merge Join [FTSwordDef] with (nolock)
On [FTSwordDef].[ID] = [ftsIndexWordOnce].[wordID]
And [FTSwordDef].[word] like 'alpha'
INTERSECT
select distinct [ftsIndexWordOnce].[sID]
from [ftsIndexWordOnce] with (nolock)
Inner Merge Join [FTSwordDef] with (nolock)
On [FTSwordDef].[ID] = [ftsIndexWordOnce].[wordID]
And [FTSwordDef].[word] like 'beta'
The query optimizer still goes stupid at 5 or more but this forces the first join to be a merge and saves it.