2009-11-09 24 views
6

Ich habe ein großes Leistungsproblem in Linq zu SQL entdeckt.Linq zu SQL nvarchar Problem

Bei der Auswahl aus einer Tabelle mit Strings sind die an sql-Server übergebenen Parameter immer nvarchar, auch wenn die Tabelle sql ein varchar ist. Dies führt zu Tabellen-Scans anstelle von Suchvorgängen, was ein enormes Leistungsproblem darstellt.

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

var qa = q.ToArray(); 

Der Parameter wird als nvarchar durchlaufen, die in den gesamten Index führt, dass von VARCHAR umgewandelt, bevor sie nvarchar verwendet wird.

Wenn der Parameter ein Varchar ist, ist es eine sehr schnelle Suche.

Gibt es eine Möglichkeit, dies zu überschreiben oder zu ändern?

Dank Grüße Craig.

+0

Wie sieht Ihre DBML aus? – RobS

+0

Es ist eine Varchar-Spalte, keine Nvarchar-Spalte. create table test (Test varchar (200) nicht null) Index erstellen ixtest on test (Test) – Craig

+0

Der Datenbankabfrageplan verwendet CONVERT_IMPLICIT und einen Scan anstelle einer Suche. Ich denke, es ist ein häufiges LINQ to SQL-Problem. Ich bin auf der Suche nach einer Problemumgehung, mit der Parameter korrekt angegeben werden können. varchar (200) anstelle von nvarchar (4), was zur Konvertierung führt. – Craig

Antwort

8

Hmmm. Dies war ein bekannter Fehler bei RTM-Builds von LINQ-to-SQL, aber aufgrund dessen, was ich online gelesen habe, war dies ein festes Problem für Gleichheitsvergleiche in RTM (obwohl es immer noch für Contains() -Vergleiche unterbrochen ist).

Egal, hier ist ein Thread auf MSDN Foren mit einigen Workarounds beschrieben: http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/4276ecd2-31ff-4cd0-82ea-7a22ce25308b

Die Abhilfe, die ich am meisten mag, ist diese:

//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, ein anderer Fall, dass ich das passiert in einer sah, war Tabelle mit ungerader Verteilung von Werten (z. B. 50% der Tabelle hatten den gleichen Wert), was bedeutet, dass ein Tabellenscan der beste verfügbare Plan war, wenn der Parameter SQL Server zum Zeitpunkt der Plankompilierung unbekannt war. Wenn Ihre Distribution ebenfalls ungewöhnlich ist, funktionieren die oben genannten Problemumgehungen nicht, da der Scan nicht von der fehlenden Konvertierung, sondern von der Parametrisierung selbst stammt. In diesem Fall wäre die einzige Problemumgehung, die ich kennen würde, die Verwendung eines OPTIMIZE FOR-Hinweises und die manuelle Angabe des SQL.

+0

+1 .. :) Hier ist ein weiterer MSDN-Thread, auch mit einigen alternativen Problemumgehungen: http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/20d456f0-9174-4745-bbc5-571f68879e27 – KristoferA

+0

Danke. Ich habe festgestellt, dass es ein Problem ist nur mit enthält. Ich dachte zuerst, es wäre breiter. – Craig