2009-11-09 14 views
6

Ho scoperto un enorme problema di prestazioni in Linq in SQL.Problema nvarchar da Linq a SQL

Quando si seleziona da una tabella utilizzando stringhe, i parametri passati a SQL Server sono sempre nvarchar, anche quando la tabella sql è un varchar. Ciò si traduce in scansioni di tabelle anziché ricerche, un enorme problema di prestazioni.

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

var qa = q.ToArray(); 

Il parametro viene passato attraverso un nvarchar, che determina l'intero indice viene convertito da varchar a nvarchar prima di essere utilizzato.

Se il parametro è un varchar è una ricerca molto veloce.

C'è un modo per sovrascrivere o modificare questo?

Grazie Cordiali saluti Craig.

+0

come si presenta il DBML? – RobS

+0

È una colonna varchar, non una colonna nvarchar. Crea test tabella (test varchar (200) non null) creazione indice ixtest su test (test) – Craig

+0

Il piano di query del database utilizza CONVERT_IMPLICIT e una scansione anziché una ricerca. Penso che sia un problema comune LINQ a SQL. Sto cercando una soluzione che permetta di specificare i parametri correttamente. varchar (200) invece su nvarchar (4) che risulta nella conversione. – Craig

risposta

8

Hmmm. Si trattava di un bug noto con build pre-RTM di LINQ-to-SQL, ma da quello che ho letto online questo era un problema fisso per i confronti di uguaglianza in RTM (sebbene ancora rotto per i confronti di Contains()).

Indipendentemente da ciò, ecco un thread sul forum di MSDN con alcune soluzioni dettagliate: http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/4276ecd2-31ff-4cd0-82ea-7a22ce25308b

La soluzione che mi piace di più è questa:

//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 altro caso ho visto che questo accada era in un tabella con distribuzione dispari di valori (ad es. il 50% della tabella aveva lo stesso valore), il che significa che, dato il parametro sconosciuto a SQL Server al momento della compilazione del piano, una scansione della tabella era il miglior piano disponibile. Se la tua distribuzione è anche insolita, allora le soluzioni alternative sopra non funzioneranno, poiché la scansione non proviene dalla conversione mancante, ma piuttosto dalla parametrizzazione stessa. In tal caso, l'unico rimedio che potrei sapere sarebbe quello di utilizzare un suggerimento OPTIMIZE FOR e specificare manualmente l'SQL.

+0

+1 .. :) ecco un altro thread msdn, anche con alcune alternative alternative: http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/20d456f0-9174-4745-bbc5-571f68879e27 – KristoferA

+0

Grazie. Ho capito che è un problema solo con contiene. All'inizio pensavo che fosse più ampio. – Craig