LINQ to SQL не будет генерировать sargable-запрос
Я использую LINQ To Sql (не Entity Framework), библиотеку System.Data.Linq.DataContext, попав в базу данных SQL Server 2005 и используя .NET Framework 4.
В таблице dbo.Dogs есть столбец "Active" типа CHAR (1) NULL. Если бы я писал прямой SQL, запрос был бы следующим:
SELECT * FROM dbo.Dogs where Active = 'A';
Запрос LINQ таков:
from d in myDataContext.Dogs where d.Active == 'A' select d;
SQL, который генерируется из вышеуказанного запроса LINQ, преобразует поле Active в UNICODE. Это означает, что я не могу использовать индекс в столбце dbo.Dogs.Active, значительно замедляя запрос:
SELECT [t0].Name, [t0].Active
FROM [dbo].[Dog] AS [t0]
WHERE UNICODE([t0].[Active]) = @p1
Есть ли что-нибудь, что я могу сделать, чтобы остановить Linq до Sql от вставки этого вызова UNICODE() и, таким образом, потерять преимущество моего индекса на dogs.Active)? Я попытался обернуть параметры с помощью метода EntityFunctions.AsNonUnicode(), но это не принесло пользы (он вставил CONVERT() в NVARCHAR вместо UNICODE() в сгенерированном sql), например:
...where d.Active.ToString() == EntityFunctions.AsNonUnicode('A'.ToString());
Ответы
Ответ 1
Вы можете немного взломать (как это часто требуется с LINQ to SQL и EF). Объявите свойство как NCHAR
в dbml. Надеюсь, это устранит необходимость сделать преобразование UNICODE
. Мы с легкостью обманываем L2S.
Возможно, вам также нужно вставить вызов EntityFunctions.AsNonUnicode
, чтобы сделать правую сторону не-Unicode-типом.
Вы также можете попробовать сопоставить столбец как varchar
.
Ответ 2
Linq предназначен для упрощения написания запросов и не всегда генерирует оптимальный SQL. Иногда, когда требуется высокая производительность, более эффективно записывать необработанный SQL непосредственно в базу данных, Linq datacontext поддерживает отображение результата SQL для объектов, подобных linq.
В вашем случае я бы предложил написать:
IEnumerable<Dog> results = db.ExecuteQuery<Dog>(
"SELECT * FROM dbo.Dogs where Active = {0}",
'A');
Ответ 3
Это старый вопрос, но в последнее время я столкнулся с этим.
Вместо записи
from d in myDataContext.Dogs where d.Active == 'A' select d;
Запись
from d in myDataContext.Dogs where d.Active.Equals('A') select d;
Это даст желаемый SQL без необходимости прибегать к любому из "хаков", упомянутых в других ответах. Я не могу сказать, почему точно.
Я опубликовал это как вопрос, поэтому мы посмотрим, получим ли мы хорошие ответы.
Ответ 4
Не так много можно сделать, чтобы запросы LINQ были переведены в операторы SQL, но вы можете написать хранимую процедуру, содержащую ваши запросы, и вызвать этот SP как функцию LINQ2SQL. Таким образом, вы должны в полной мере воспользоваться оптимизацией SQL Server