J'ai une table avec 117 000 enregistrements. J'ai besoin d'effectuer une recherche qui vérifie 3 champs distincts pour un modèle de chaîne donné.
Ma clause Où est la suivante: P>
field1 LIKE '%' + @DESC + '%' OR field2 LIKE '%' + @DESC + '%' OR field3 LIKE '%' + @DESC + '%'
7 Réponses :
Utiliser la recherche de texte complet et contient . Comme ne peut être optimisé lors de la recherche au milieu du champ, c'est-à-dire. Lorsque l'expression de même commence par un "%", il effectuera donc toujours une balayage de table complète. p>
Vous pouvez utiliser un index, avec un peu de travail, lorsque vous faites comme '%' + chaîne, voir le lien de mon autre commentaire.
@Km: astuce intéressante, une colonne inversée. Aussi une bonne analogie avec le carnet de téléphone, rend le cas très clairement.
Bonne truc, à Obad, il n'y a rien de similaire pour le problème "% Text%".
@Km: Il doit vraiment être un formulaire "% test%", de sorte que la méthode inverse est sortie, bien que j'ai vu cela avant et c'est une astuce intelligente. Je vais devoir essayer la recherche de texte complète, mais on dirait que je vais devoir convaincre le DBAS de l'indexer correctement. Merci pour la suggestion. Je verrai si le texte complet / contient des performances de boosts. Je me souviens de faire cela sur l'ancienne base de données avec la même requête et c'était beaucoup plus rapide ... Je ne sais pas ce que le nouveau fait différemment
Après avoir obtenu le DBA à l'index de texte complet des tables, cela m'a amené jusqu'à 1-3 secondes pour une recherche. Merci pour l'aide!
Que diriez-vous de rechercher au début de la chaîne?
Et si le paramètre passait est null?
Ceci est incorrect, comme peut être optimisé même lors de la recherche au milieu du champ.
@ M.ta Rétrécissement d'une ligne de rangée à des fins de plus petite, n'est pas une optimisation de l'index i>. Depuis que vous insistez pour faire revivre une réponse de 9 ans, vous pouvez au moins regarder une alternative moderne comme la colonne ...
@RemusRUSANU 1, je n'ai pas dit comme code> est le seul, ou la solution préférée, ou préférée. 2, avez-vous lu la page que j'ai liée? Il montre comment utiliser un index et non comment restreindre une mousse de rangement, peu importe ce que cela signifie.
Chaque fois que vous commencez une recherche comme une zone générique, vous faites un scan. Sauf si vous pouvez réduire vos critères de recherche pour inclure le premier caractère (qui peut ne pas être réalisable), vous devrez recourir à la recherche de texte complète. P>
@Stuart Ainsworth a déclaré , que les entreprises ne doivent pas être vraies, voir ceci:
Maintenant, vous jouez simplement avec la sémantique; Vous inverserez la colonne et indexez-la, puis inversez la clause de la même manière afin que cela ne commence pas par une carte générique. Vous ne démarrez pas une recherche avec une base générique, donc vous ne faites donc pas de scanner. Je vais admettre que c'est une solution intéressante et je vais devoir garder ça à l'esprit.
Ceci est incorrect, comme peut être optimisé même lors de la recherche au milieu du champ.
Donc, près de 8 ans plus tard, j'ai appris quelque chose de nouveau :) Vous n'avez jamais pensé à supprimer les valeurs NULL à partir d'une recherche de chaîne sauvage.
Que diriez-vous de
CONTAINS(field1 + field2 + field3, @DESC)
Avez-vous vraiment besoin de commencer avec une base générique? Pourquoi? Souvent, vous pouvez forcer les utilisateurs à taper dans le premier caractère au moins. J'apporte cela parce que certains développeurs utilisent simplement la couverture générique comme habitude de ne pas être une exigence. Dans la plupart des cas, les utilisateurs pourront taper le premier caractère à moins que le déposé stocke de longues chaînes (comme Selon les noms officiels de l'aéroport). Sinon, vous devez vraiment utiliser l'indexation de texte intégral, bien que le truc de KM avec l'inverse est assez cool si vous n'avez pas besoin de la carte générique à la fin. p>
Si vous pouvez éviter de faire la performance des choses, alors faites-le. P>
Oui, j'ai besoin d'un caractère générique double face pour cette requête. J'ai besoin de trouver quelque chose comme "banane" dans "yogourt de la banane à la fraise".
tandis que je suis d'accord avec la réponse acceptée selon laquelle l'indexation complète du texte serait la meilleure solution et ne préconise en aucun cas l'utilisation de recherches génériques principales si elles doivent être effectuées, alors il sont em> étapes potentielles que Peut être pris pour rendre la performance d'eux moins mal. Kalen Delaney dans le livre " Microsoft SQL Server 2008 Internals " dit: P> La collation peut faire une énorme différence
Lorsque SQL Server doit regarder presque
Tous les personnages dans les cordes. Pour
exemple, regardez les éléments suivants: p>
SELECT COUNT(*) FROM tbl WHERE longcol LIKE '%abc%'
Plus du livre "Si vous avez une colonne VARCHAR, vous pouvez accélérer cela en forçant la collance comme suit: Sélectionnez Compte (*) à partir de TBL où Longcol rassemble SQL_Latin1_general_cp_ci_as comme '% ABC%';"
@Yoelhalb vous avez probablement signifié _cp1 _ code> pas
_cp _ code>
J'ai essayé une solution possible. Avant cette solution, même la requête ne renvoyait pas le résultat et provoquant une erreur de délai de connexion.
Ma requête utilisait le filtre de date et d'autres critères. Tous les autres critères étaient comme la recherche. Un mot clé de colonne recherchait une recherche comme "% abc%" sur la colonne NText et il faisait une balayage de la table complète. P>
solution: p>
Diviser la requête en 2 parties. 1) PREMIÈRE PARTIE DANS LE CTE (COMMANDE TABLE EXPRESS) 2) Appliquez tous les critères de recherche sur CTE. P>
WITH SearchData(Column1,Column2,Column3,Column4,........) AS ( SELECT Column1,Column2,Column3,Column4,........... FROM myTable1 WITH(NOLOCK) INNER JOIN MyTable2 WITH(NOLOCK) ON MyTable1.id = MyTable2.Id WHERE (MyTable1.CreationTime >= '2014-04-27' AND MyTable1.CreationTime <= '2014-05-01') ) SELECT DISTINCT top 250 Column1,Column2,Column3,Column4 FROM SearchData WHERE (ISNULL(Column1,'') LIKE @Column1 +'%' OR @Column1 IS NULL) and (Column2 LIKE @Column2+ '%' OR @Column2 IS NULL) ... ... ... ... AND (Column10 like '%'+@Column10+'%' or @Column10 IS NULL) AND @Column1+@Column2+@Column3+........@Column10 <> '' ORDER BY [CreationTime] DESC
Je pense que l'utilisation de la clause TOP code> avec une requête qui a une condition similaire aura toujours la performance. Donc, c'est la clause supérieure plutôt qu'un CTE qui contribue au gain de performance, car avec le haut d'une analyse complète est réduit bref dès que le nombre requis d'enregistrements est numérisé.
En tant que note hors sujets utilisant avec (NOLOCK) dans chaque join est très dangereuse, vous devez faire très attention à cela ou vous obtiendrez des données dupliquées, etc. Je vois que les gens truquent cette indice comme un moyen standard d'optimisation des requêtes, ce n'est pas . Vous devriez toujours réfléchir à deux fois et examiner la manière dont les tables sont écrites (insérées / update) dans votre application avant de peser dans une indication Nolock. (Dire juste)
Si vous ne pouvez pas utiliser Fulltextsearch, vous pouvez augmenter la vitesse dans 10 fois. Faire ensuite:
1 Ajouter un champ calculé: p> 2 Ajouter un index pour le champ calculé: p> select count(*)
from TableName
where CalculatedColumnName like '%' + upper(@ParameterValue) + '%' collate Latin1_General_100_Bin2