FreeText La requête est lente - et comprend TOP Trier par
-
02-10-2019 - |
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é.
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 commeXML
- Utilisez
sp_create_plan_guide
avec unOPTION 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:
-
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. "
-
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
-
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.