LIKE vs CONTAINS sur SQL Server

210

Laquelle des requêtes suivantes est la plus rapide (LIKE vs CONTAINS)?

SELECT * FROM table WHERE Column LIKE '%test%';

ou

SELECT * FROM table WHERE Contains(Column, "test");
user667429
la source
12
Acceptez une réponse, voulez-vous?
AgentFire
7
Il n'a pas été depuis des années l'homme.
Chris

Réponses:

174

La seconde (en supposant que vous voulez dire CONTAINS, et en fait la mettre dans une requête valide) devrait être plus rapide, car elle peut utiliser une certaine forme d'index (dans ce cas, un index de texte intégral). Bien entendu, cette forme de requête n'est disponible que si la colonne se trouve dans un index de texte intégral. Si ce n'est pas le cas, seul le premier formulaire est disponible.

La première requête, utilisant LIKE, ne pourra pas utiliser d'index, car elle commence par un caractère générique, et nécessitera donc toujours une analyse complète de la table.


La CONTAINSrequête doit être:

SELECT * FROM table WHERE CONTAINS(Column, 'test');
Damien_The_Unbeliever
la source
@edze - vous voulez dire, la même page qui est déjà liée pour être ma première mention CONTAINS? Qu'en est-il? La forme originale de la question ne Column CONTAIN("%test%",Column)>0devait pas du tout être valable. Ce n'est toujours pas tout à fait raison.
Damien_The_Unbeliever
Cela nous a aidés à trier une requête sur SharePoint. Ayez un autre badge Great Answer.
ouflak
14

Après avoir exécuté les deux requêtes sur une instance SQL Server 2012, je peux confirmer que la première requête a été la plus rapide dans mon cas.

La requête avec le LIKEmot clé a montré une analyse d'index en cluster.

Le CONTAINSavait également une analyse d'index en cluster avec des opérateurs supplémentaires pour la correspondance de texte intégral et une jointure de fusion.

Plan

MI C
la source
8
Les pages feuilles d'index cluster sont le tableau. Une LIKErequête avec un caractère générique de début ne pourra pas utiliser efficacement la partie d'index. Il faudra simplement scanner le tout. Bien qu'il puisse sans doute y avoir des circonstances dans lesquelles l'analyse CI complète fonctionne mieux qu'une requête utilisant l'index de texte intégral (peut-être si une proportion très élevée de lignes correspond par exemple), ce sera en grande partie l'exception pas une règle générale que vous "pouvez confirmer" ".
Martin Smith
Eh bien, je regarde un plan d'exécution réel récupérant plus de 200 000 enregistrements. Placer les deux requêtes dans un lot, les deux ont analysé l'index cluster, mais en plus la requête "CONTAINS" a un coût supplémentaire de FULL TEXT MATCH et un MERGE JOIN.
MI C
S'il choisit une jointure de fusion, SQL Server estime que plus de x% des lignes finiront par correspondre au prédicat. (Où X = le point de basculement ). Dans ce cas, j'imagine que les deux pourraient se retrouver assez uniformément. Les coûts indiqués dans le plan d'exécution ne sont que des estimations (même dans le plan réel). Bien qu'il existe d'autres opérateurs de plan d'exécution dans le plan FT, il présente certains avantages. La jointure de fusion peut s'arrêter avant la fin de l'analyse lorsqu'elle manque de résultats FT et elle n'a pas non plus à évaluer la LIKE.
Martin Smith
1
J'ai exécuté une requête similaire pour vérifier le plan d'exécution dans SQL 2012 et cela m'a donné une recherche d'index. Peut-être que dans l'exemple ici, la table était presque vide. Dans certains cas, sql utilise un scan d'index dans une très petite table à la place pour utiliser l'index car il est plus rapide.
Juan
8

Je pense que cela a CONTAINSpris plus de temps et utilisé Mergeparce que vous aviez un tiret ("-") dans votre requête adventure-works.com.

Le tiret est un mot de coupure, donc la CONTAINSrecherche dans l'index de texte intégral adventureet la recherche works.comet la fusion des résultats.

Omri Valfer
la source
8

Essayez également de changer à partir de ceci:

    SELECT * FROM table WHERE Contains(Column, "test") > 0;

Pour ça:

    SELECT * FROM table WHERE Contains(Column, '"*test*"') > 0;

Le premier trouvera des enregistrements avec des valeurs comme " ceci est un test " et " un cas de test est le plan ".

Ce dernier trouvera également des enregistrements avec des valeurs comme " je teste ceci " et " c'est le plus grand ".

John Doe
la source
4
Est-ce que mettre l'astérisque avant et après le terme de recherche fonctionne? En lisant la documentation de CONTAINS, il ne mentionne que l'utilisation de termes préfixes comme 'test *', pas de termes suffixes comme ' test' et pas de recherche de sous-chaîne complète comme '* test '. Mais je ne l'ai pas essayé.
mat forsythe
5
Si vous lisez la documentation de CONTAINS ( docs.microsoft.com/en-us/sql/t-sql/queries/… ), seule la recherche de préfixes est prise en charge. J'ai essayé cela de nombreuses fois expérimentalement et il n'est pas possible de trouver "c'est le plus grand" (dans SQL Sever) avec Contains (Column, '" test "')
cl0rkster