Question

Le tableau de produit a 700K enregistrements en elle. La requête:

SELECT TOP 1 ID, Name FROM Product WHERE contains(Name, '"White Dress"') ORDER BY DateMadeNew desc

prend environ 1 minute à terme. Il y a un index non ordonnés en clusters sur l'indice DateMadeNew et FreeText sur Nom.

Si je retire TOP 1 ou par -. Il faut moins de 1 seconde à courir

Voici le lien vers le plan d'exécution. http://screencast.com/t/ZDczMzg5N

On dirait FullTextMatch a plus de 400K exécutions. Pourquoi cela arrive-t-il? Comment peut-il être plus rapide?

Mise à jour 5/3/2010

On dirait cardinalité est détraqué sur plusieurs recherches mot FREETEXT:

Optimizer estime qu'il ya 28K dossiers correspondant à « White Dress », alors qu'en réalité il n'y a que 1. http://screencast.com/t/NjM3ZjE4NjAt

Si je remplace 'White Dress' avec 'blanc', le nombre est estimé '27, 951' , alors que nombre réel est '28, 487' qui est beaucoup mieux.

Il semble que l'Optimiseur utilise uniquement le premier mot de la phrase recherchée cardinalité.

Était-ce utile?

La solution

Modifier

De http://technet.microsoft.com/en- nous / bibliothèque / cc721269.aspx # _Toc202506240

  

La chose la plus importante est que la   type correct est choisi pour rejoindre   requête de texte intégral. cardinalité   estimation sur la FulltextMatch STVF   est très important pour le bon plan.   La première chose à vérifier est la   estimation FulltextMatch de cardinalité.   Ceci est le nombre estimé de hits   dans l'index de recherche en texte intégral   chaîne. Par exemple, dans la requête en   La figure 3 cela devrait être proche de la   nombre de documents contenant le   « Mot » terme. Dans la plupart des cas, il devrait   être très précis, mais si l'estimation   était hors d'un long chemin, vous pourriez   générer des mauvais plans. L'estimation pour   termes simples est généralement très bon,   mais l'estimation de plusieurs termes tels que   phrases ou et des requêtes est plus complexe   car il est impossible de savoir ce que   l'intersection des termes de l'indice   sera basé sur la fréquence du   termes de l'indice. Si la cardinalité   l'estimation est bon, un mauvais plan   est probablement causée par la requête   modèle de coût de l'optimiseur. La seule façon de   résoudre le problème du plan est d'utiliser une requête   allusion à la force d'un certain type de jointure   ou OPTIMIZE.

Il ne peut tout simplement pas savoir à partir des informations qu'il stocke si les 2 termes de recherche ensemble risquent d'être tout à fait indépendant ou souvent trouvé ensemble. Peut-être vous devriez avoir 2 procédures distinctes l'une pour les requêtes individuelles de mots que vous laissez l'Optimiseur de faire son truc sur et un pour les procédures de mots multiples que vous forcez un plan « assez bon » sur (sys.dm_fts_index_keywords pourrait aider si vous ne voulez pas taille unique régime).

NB:. Votre procédure unique mot aurait probablement besoin de l'option WITH RECOMPILE regardant ce petit morceau de l'article

  

Dans SQL Server 2008 texte intégral recherche, nous avons la possibilité de modifier le plan qui est généré sur la base d'une estimation de cardinalité du terme de recherche utilisé. Si le plan de requête est fixe (comme dans une requête paramétrées dans une procédure stockée), cette étape n'a pas lieu. Par conséquent, le plan compilé sert toujours cette requête, même si ce plan est pas idéal pour un terme de recherche donné.

Réponse originale

Votre nouveau plan semble encore assez mauvais cependant. On dirait qu'il revient seulement 1 rangée de la partie pleine de requête de texte, mais l'analyse de tous 770159 lignes dans la table de produit.

Comment cela effectuer?

CREATE TABLE #tempResults
(
ID int primary key,
Name varchar(200),
DateMadeNew datetime
)

INSERT INTO #tempResults
SELECT 
      ID, Name, DateMadeNew 
      FROM Product 
      WHERE contains(Name, '"White Dress"')


SELECT TOP 1
    *
    FROM #tempResults
    ORDER BY DateMadeNew desc

Autres conseils

Je ne peux pas voir le plan d'exécution lié, la police du réseau sont de blocage qui, si cela est juste une supposition ...

si elle est en cours d'exécution rapide sans TOP et ORDER BY, essayez de faire ceci:

SELECT TOP 1
    *
    FROM (SELECT 
              ID, Name, DateMadeNew 
              FROM Product 
              WHERE contains(Name, '"White Dress"')
         ) dt
    ORDER BY DateMadeNew desc
  

On dirait FullTextMatch a plus de 400K exécutions. Pourquoi est-ce qui se passe?

Puisque vous avez un indice combiné avec TOP 1, optimiseur pense qu'il sera préférable de parcourir l'index, en vérifiant chaque enregistrement pour l'entrée.

  

Comment peut-il être plus rapide?

Si la mise à jour des statistiques ne l'aide, essayez d'ajouter une touche à votre requête:

SELECT  TOP 1 *
FROM    product pt
WHERE   CONTAINS(name, '"test1"')
ORDER BY
        datemadenew DESC
OPTION (HASH JOIN)

Cela va forcer le moteur à utiliser un algorithme de HASH JOIN pour se joindre à votre table et la sortie de la requête texte intégral.

Fulltext requête est considérée comme une source distante retournant l'ensemble de valeurs indexées par KEY INDEX fournies dans la définition de FULLTEXT INDEX.

Mise à jour:

Si vos utilisations ORM paramétrés requêtes, vous pouvez créer un guide de plan.

  • Utilisez Profiler pour intercepter la requête que le ORM envoie verbatim
  • Générer un plan correct SSMS à l'aide des conseils et de l'enregistrer comme XML
  • Utilisez sp_create_plan_guide avec un OPTION USE PLAN pour forcer l'optimiseur toujours utiliser ce plan.

J'ai eu le même problème plus tôt.

La performance dépend de l'index unique que vous choisissez pour l'indexation en texte intégral. Ma table a deux colonnes uniques -. ID et article_number

La requête:

select top 50 id, article_number, name, ... 
from ARTICLE 
CONTAINS(*,'"BLACK*" AND "WHITE*"')
ORDER BY ARTICLE_NUMBER

Si l'index en texte intégral est connecté à ID il est lent selon les mots recherchés. Si l'index en texte intégral est connecté à l'index de ARTICLE_NUMBER UNIQUE alors il était toujours rapide.

Je meilleure solution.

. première vue d'ensemble Let solutions proposées car ils peuvent également être utilisés dans certains cas:

  1. OPTION (HASH JOIN) - n'est pas bon que vous pouvez obtenir l'erreur "processeur de requête ne pouvait pas produire un plan de requête en raison des indices définis dans cette requête Resoumettre la requête sans spécifier de notes et sans. en utilisant SET FORCEPLAN. "

  2. SELECT TOP 1 * FROM (ORIGINAL_SELECT) ORDER BY ... - n'est pas bon, quand vous avez besoin d'utiliser les résultats de paginer vous ORIGINAL_SELECT

  3. sp_create_plan_guide - n'est pas bon, à l'utilisation plan_guide vous devez planifier enregistrer pour instruction SQL spécifique, cela ne fonctionnera pas pour les instructions SQL dynamiques (par exemple généré par ORM)

II. Ma solution contient deux parties     1. jointure réflexive table utilisée pour la recherche de texte intégral     2. Utilisez MS SQL HASH MSDN Rejoindre Conseils

Votre SQL:

SELECT TOP 1 ID, Name FROM Product WHERE contains(Name, '"White Dress"') 
ORDER BY DateMadeNew desc

devrait être reformulé comme:

SELECT TOP 1 p.ID, p.Name FROM Product p INNER HASH JOIN Product fts ON fts.ID = p.ID
WHERE contains(fts.Name, '"White Dress"') 
ORDER BY p.DateMadeNew desc

Si vous utilisez NHibernate avec / sans château actifs Records, j'ai répondu dans

Quelques réflexions sur celui-ci:

1) Avez-vous mis à jour les statistiques sur la table de produit? Il serait utile de voir les estimations et le nombre réel de lignes sur les opérations là aussi.

2) Quelle version de SQL Server utilisez-vous? J'ai eu un problème similaire avec SQL Server 2008 qui est avéré être rien de plus que de ne pas avoir installé le Service Pack 1. Installez SP1 et une requête FreeText qui a pris quelques minutes (en raison d'un grand nombre d'exécutions réelles contre réelles) sont allés jusqu'à prendre une seconde.

scroll top