Подтвердить что ты не робот

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());
4b9b3361

Ответ 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