2009-11-04 2 views
2

J'ai une situation où une certaine requête linq qui s'exécute sur une table de plusieurs millions de lignes prend beaucoup de temps à s'exécuter. J'ai disséqué la sortie de la requête linq et trouvé qu'il créait les paramètres de la clause where en utilisant le mauvais type de données. Par exemple, un champ a été défini comme Char (12) dans la base de données, mais le paramètre avec lequel il comparait a été déclaré NVarChar (12). Une fois que j'ai changé la requête pour utiliser Char au lieu de NVarChar, il a couru sous-seconde comme il se doit. Existe-t-il un moyen d'obtenir linq to sql pour utiliser le type de données correct tel que défini dans le fichier .dbml pour cette colonne? J'ai vérifié et défini comme DbType = "Char (12)" dans le fichier .dbml de contexte de données.Comment forcer linq à sql à utiliser le type de données correct pour les paramètres sql?

+0

Je me demande si vous avez un mauvais plan d'exécution mises en cache parce que nvarchar (12) et le charbon (12) ne doivent pas faire grande différence. Au moins, je ne pense pas qu'ils devraient. –

+0

Après avoir testé un peu, c'est sûr. J'ai effacé le cache de requête avant chaque exécution et il est passé de 4 secondes à 20ms juste en changeant le type de données. Je suis même allé jusqu'à convertir mon appel linq en sql en une requête sql old et j'ai utilisé la méthode .ExecuteQuery() du contexte de données pour l'exécuter et il fonctionne rapidement. C'est définitivement un problème de conversion de type de données qui fait que SQL ignore les index sur la table. – Jason

Répondre

2

Vous pouvez obtenir la commande et réinitialiser directement les types de paramètres (à ansi-string dans votre cas).

http://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.getcommand.aspx http://msdn.microsoft.com/en-us/library/system.data.dbtype.aspx

alors vous pourriez appeler ExecuteReader sur cette commande, ce qui donne un DbDataReader. Vous pouvez transmettre ce DbDataReader à la méthode Translate de votre datacontext, et il vous donnera le IEnumerable<T> que vous attendez de linq.

http://msdn.microsoft.com/en-us/library/bb534213.aspx


Le problème de performance est causée par le paramètre de requête ayant un type différent de l'indice sélectionné par l'optimiseur de requête. Ce qui se passe ensuite est que l'index entier est converti en le type du paramètre. Ceci est fait à chaque fois que la requête est émise - la conversion ne traîne pas pour une requête ultérieure.

Je vois souvent ce comportement lors de l'envoi d'une collection de chaînes dans la base de données:

//this query will get correct parameter type 
db.Customers.Where(c => c.Name == "Bob") 
    //this query can get incorrect parameter type 
List<string> names = new List<string>(){"Amy", "Bob"}; 
db.Customers.Where(c => names.Contains(c.Name));