2010-03-05 4 views
3

J'ai une table avec une colonne indexée en texte intégral MiddlePart. La table compte environ 600 000 lignes. La requête suivante est très rapide (30 résultats, < 1 seconde):Pourquoi ma requête est-elle si lente? (Bizarrerie de recherche de texte intégral SQL Server 2008)

select * from DomainName 
where contains (MiddlePart, '"antiques*"') 
    OR freetext(MiddlePart, 'antiques') 

Cette requête est également très rapide (5 résultats, < 1 seconde):

select * from DomainName 
where (contains (MiddlePart, '"dog*"') OR freetext(MiddlePart, 'dog')) 
    AND (contains (MiddlePart, '"training*"') OR freetext(MiddlePart, 'training')) 

Alors pourquoi sont à la fois ces requêtes DÉPASSE Lentement? (90 secondes + et j'annulé la requête):

Recherche A:

select * from DomainName 
where contains (MiddlePart, '"antiques*"') 
    OR freetext(MiddlePart, 'antiques') 
union 
select * from DomainName 
where (contains (MiddlePart, '"dog*"') OR freetext(MiddlePart, 'dog')) 
    AND (contains (MiddlePart, '"training*"') OR freetext(MiddlePart, 'training')) 

Recherche B:

select * from DomainName 
where (contains (MiddlePart, '"antiques*"') 
    OR freetext(MiddlePart, 'antiques')) 
OR 
    ((contains (MiddlePart, '"dog*"') OR freetext(MiddlePart, 'dog')) 
    AND (contains (MiddlePart, '"training*"') OR freetext(MiddlePart, 'training'))) 

EDIT

plan de texte complet pour QUERY A:

|--Merge Join(Union) 
    |--Nested Loops(Inner Join, OUTER REFERENCES:(FulltextMatch.[docid], [Expr1055]) WITH ORDERED PREFETCH) 
    | |--Stream Aggregate(GROUP BY:(FulltextMatch.[docid])) 
    | | |--Merge Join(Concatenation) 
    | |   |--Table-valued function 
    | |   |--Table-valued function 
    | |--Clustered Index Seek(OBJECT:([domaining].[dbo].[DomainName].[PK__DomainNa__3214EC2708EA5793]), SEEK:([domaining].[dbo].[DomainName].[ID]=FulltextMatch.[docid]) ORDERED FORWARD) 
    |--Merge Join(Left Semi Join, MERGE:([domaining].[dbo].[DomainName].[ID])=(FulltextMatch.[docid]), RESIDUAL:([domaining].[dbo].[DomainName].[ID]=FulltextMatch.[docid])) 
     |--Nested Loops(Inner Join, OUTER REFERENCES:(FulltextMatch.[docid], [Expr1056]) WITH ORDERED PREFETCH) 
     | |--Stream Aggregate(GROUP BY:(FulltextMatch.[docid])) 
     | | |--Merge Join(Concatenation) 
     | |   |--Table-valued function 
     | |   |--Table-valued function 
     | |--Clustered Index Seek(OBJECT:([domaining].[dbo].[DomainName].[PK__DomainNa__3214EC2708EA5793]), SEEK:([domaining].[dbo].[DomainName].[ID]=FulltextMatch.[docid]) ORDERED FORWARD) 
     |--Merge Join(Concatenation) 
      |--Table-valued function 
      |--Table-valued function 

plan de texte intégral pour la requête B:

|--Nested Loops(Left Semi Join, OUTER REFERENCES:([domaining].[dbo].[DomainName].[ID])) 
    |--Clustered Index Scan(OBJECT:([domaining].[dbo].[DomainName].[PK__DomainNa__3214EC2708EA5793])) 
    |--Concatenation 
     |--Table-valued function 
     |--Nested Loops(Left Semi Join) 
     | |--Concatenation 
     | | |--Table-valued function 
     | | |--Table-valued function 
     | |--Row Count Spool 
     |   |--Concatenation 
     |    |--Table-valued function 
     |    |--Table-valued function 
     |--Table-valued function 
+0

Avez-vous essayé de changer le premier à « UNION ALL » au lieu de « UNION »? Avez-vous regardé les plans de requête? L'utilisation de prédicats "OR" peut vraiment gâcher un plan de requête. – Pointy

+0

Pourriez-vous s'il vous plaît signaler les plans de requête pour les requêtes? Il suffit de lancer 'SET SHOWPLAN_TEXT ON', puis d'exécuter les requêtes. – Quassnoi

+1

@OMGPonies: "J'ai une table avec une colonne indexée en texte intégral" MiddlePart "" :) – Quassnoi

Répondre

2

Puisque vous n'avez pas inclus SHOWPLAN pour la requête combinée, je suppose qu'il n'a pas une sortie, ce qui indiquerait un bogue dans l'optimiseur. Cela a été connu pour se produire dans d'autres endroits.

Dans tous les cas, les tables temporaires sont toujours un choix respectable face à cette bizarrerie:

select * into #a from DomainName 
where contains (MiddlePart, '"antiques*"') 
    OR freetext(MiddlePart, 'antiques') 

select * into #b from DomainName 
where (contains (MiddlePart, '"dog*"') OR freetext(MiddlePart, 'dog')) 
    AND (contains (MiddlePart, '"training*"') OR freetext(MiddlePart, 'training')) 

select * from #a union #b 
Questions connexes