2009-01-29 9 views
6

Compte tenu de cette requête LINQ contre un contexte de données EF:SQL produit par Entity Framework pour faire correspondre la chaîne

var customers = data.Customers.Where(c => c.EmailDomain.StartsWith(term)) 

Vous vous attendez à produire SQL comme ça, non?

SELECT {cols} FROM Customers WHERE EmailDomain LIKE @term+’%’ 

Eh bien, en fait, il fait quelque chose comme ceci:

SELECT {cols} FROM Customer WHERE ((CAST(CHARINDEX(@term, EmailDomain) AS int)) = 1) 

Savez-vous pourquoi?

En outre, le remplacement Où sélecteur:

c => c.EmailDomain.Substring(0, term.Length) == term 

il fonctionne 10 fois plus rapide, mais produit encore un peu SQL assez dégueu. Linq to SQL traduit correctement StartsWith en Like {term}%, et nHibernate a une LikeExpression dédiée.

+0

Avez-vous vu comment l'assemblage dégueu ou MSIL obtient après votre jolie LINQ ou tout bon code C# source? La question est de savoir si cela donne un résultat correct, pourquoi avons-nous besoin de déranger. –

+0

Merci pour le conseil sur le remplacement de StartsWith avec Substring - qui a résolu mon problème avec la version de StartsWith ne correspondant pas aux chaînes vides comme préfixes. –

+0

duplication possible de [linq à entités générées sql] (http://stackoverflow.com/questions/576803/linq-to-entities-generated-sql) – brechtvhb

Répondre

3

La raison en est que CharIndex est beaucoup plus rapide et plus propre à exécuter que SQL que LIKE. La raison en est, que vous pouvez avoir certaines clauses "LIKE" fou. Exemple:

SELECT * FROM Customer WHERE EmailDomain LIKE 'abc%de%sss%' 

Mais, la fonction « CHARINDEX » (qui est essentiellement « IndexOf ») prend en compte que trouver la première instance d'un ensemble de caractères ... les caractères génériques sont autorisés.

Donc, il y a votre réponse :)

EDIT: Je voulais juste ajouter que j'encourage les gens à utiliser CHARINDEX dans leurs requêtes SQL pour des choses qu'ils ne ont pas besoin « LIKE » pour. Il est important de noter cependant que dans SQL Server 2000 ... un champ "Texte" peut utiliser la méthode LIKE, mais pas CHARINDEX.

+5

Alors qu'un Like peut être plus lent qu'un CharIndex, il est beaucoup plus rapide quand utilisé dans le contexte de StartsWith (ie Like {term}%). Dans ce cas, l'optimiseur de requête peut utiliser les indices existants. – thatismatt

+0

"La raison en est que CharIndex est beaucoup plus rapide et plus propre à SQL que LIKE." Ce n'est pas une déclaration valide. Les gens utilisent le plus souvent seulement un ou deux% signes dans leur LIKE, et un caractère générique de fin seulement (par exemple LIKE 'xxx%') permet d'utiliser l'index, alors que CHARINDEX force une analyse de table. – influent

0

Les performances semblent être à peu près égales entre LIKE et CHARINDEX, ce qui ne devrait pas être la raison. Voir here ou here pour une discussion. Le CAST est aussi très bizarre car CHARINDEX renvoie un int.

+0

Les caractères génériques de fin de liste (LIKE 'xxx%') peuvent utiliser des recherches d'index. CHARINDEX non, donc c'est un exemple parfait où les performances peuvent être de loin supérieures pour LIKE (ce qui est indiqué dans votre premier lien). Mais je suis d'accord que le CAST est confus. – influent

0

Je suis d'accord qu'il n'est pas plus rapide, je récupérais des dizaines de milliers de lignes de notre base de données avec la lettre au nom. Je ne trouve cependant que vous devez utiliser> = plutôt que ... donc utiliser

{cols} FROM Customer WHERE ((CAST(CHARINDEX(@term, EmailDomain) AS int)) > 0) 

plutôt que

{cols} FROM Customer WHERE ((CAST(CHARINDEX(@term, EmailDomain) AS int)) = 1) 

Voici mes deux tests ....

select * from members where surname like '%i%' --12 seconds 

select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) > 0) --12 seconds 

select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) = 1) --too few results 
Questions connexes