2009-11-09 6 views
6

J'ai découvert un énorme problème de performance dans Linq to SQL.Linq to SQL nvarchar problème

Lors de la sélection à partir d'une table à l'aide de chaînes, les paramètres transmis au serveur SQL sont toujours nvarchar, même si la table sql est un varchar. Cela se traduit par des scans de table au lieu de chercher, un problème de performance massif.

var q = (
    from a in tbl 
    where a.index == "TEST" 
    select a) 

var qa = q.ToArray(); 

Le paramètre est passé à travers un nvarchar, qui se traduit par l'indice entier étant converti à partir de varchar nvarchar avant d'être utilisé.

Si le paramètre est un varchar c'est une recherche très rapide.

Existe-t-il un moyen de remplacer ou de modifier cela?

Merci Cordialement Craig.

+0

à quoi ressemble votre DBML? – RobS

+0

C'est une colonne varchar, pas une colonne nvarchar. create test de table (test varchar (200) non null) create index ixtest on test (test) – Craig

+0

Le plan de requête de base de données utilise CONVERT_IMPLICIT et un scan au lieu d'une recherche. Je pense que c'est un problème commun de LINQ à SQL. Je suis à la recherche d'une solution de contournement qui permettra de spécifier correctement les paramètres. varchar (200) à la place sur nvarchar (4) qui entraîne la conversion. – Craig

Répondre

8

Hmmm. C'était un bug connu avec les versions pré-RTM de LINQ-to-SQL, mais d'après ce que j'ai lu en ligne c'était un problème fixe pour les comparaisons d'égalité dans RTM (bien que toujours cassé pour les comparaisons Contains()).

Quoiqu'il en soit, voici un fil sur les forums MSDN avec des solutions de contournement détaillées: http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/4276ecd2-31ff-4cd0-82ea-7a22ce25308b

La solution que je préfère est celui-ci:

//define a query 
IQueryable<Employee> emps = from emp in dc2.Employees where emp.NationalIDNumber == "abc" select emp; 

//get hold of the SQL command translation of the query... 
System.Data.Common.DbCommand command = dc2.GetCommand(emps); 

//change param type from "string" (nvarchar) to "ansistring" (varchar) 
command.Parameters[0].DbType = DbType.AnsiString; 
command.Connection = dc2.Connection; 

//run 
IEnumerable<Employee> emps2 = dc2.Translate<Employee>(command.ExecuteReader()); 

BTW, un autre cas, je voyais ce qui se passe était dans un ce qui signifie que, étant donné que le paramètre est inconnu de SQL Server au moment de la compilation du plan, une analyse de table était le meilleur plan disponible. Si votre distribution est également inhabituelle, les solutions de contournement ci-dessus ne fonctionneront pas, car l'analyse ne proviendra pas de la conversion manquante, mais plutôt du paramétrage lui-même. Dans ce cas, la seule solution de contournement que je connaîtrais serait d'utiliser un indicateur OPTIMIZE FOR et de spécifier manuellement le code SQL.

+0

+1 .. :) Voici un autre fil msdn, également avec d'autres solutions de contournement: http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/20d456f0-9174-4745-bbc5-571f68879e27 – KristoferA

+0

Merci. J'ai réalisé que c'est un problème seulement avec contient. Je pensais que c'était plus large au début. – Craig