CompiledQuery против простого генерации SQL Linq - PullRequest
2 голосов
/ 31 марта 2009

Итак, я проводил профилирование различных способов обращения к моей базе данных SQLServer. Я сделал ванильный TSQL, CompiledQuery и некомпилированный оператор Linq.

Производительность прошла в том же порядке, как и ожидалось, но я заметил кое-что любопытное при профилировании последних двух.

SQL, сгенерированный CompiledQuery, был НАМНОГО лучше, чем сгенерированный простым старым оператором.

Локальная база данных SQLExpress; таблица называется foreignTable, ColumnA - это int, первичный ключ (индексируется); ColumnB является случайным int.

Func<testingDatabaseEntities1, int, int> GetByPK = CompiledQuery.Compile((testingDatabaseEntities1 ft, int key) 
  => (ft.foreignTable.Where(x => x.ColumnA == key).FirstOrDefault().ColumnB));

Генерирует

SELECT 
[Project1].[ColumnB] AS [ColumnB]
FROM   ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN  (SELECT TOP (1) 
    [Extent1].[ColumnB] AS [ColumnB]
    FROM [dbo].[foreignTable] AS [Extent1]
    WHERE [Extent1].[ColumnA] = @p__linq__1 ) AS [Project1] ON 1 = 1

Что для сгенерированного кода действительно не слишком ужасно.

Но когда я делаю простое утверждение Linq:

entity.foreignTable.Where(x => x.ColumnA == searchForMe).FirstOrDefault().ColumnB

генерирует:

SELECT 
[Limit1].[C1] AS [C1], 
[Limit1].[ColumnA] AS [ColumnA], 
[Limit1].[ColumnB] AS [ColumnB], 
[Limit1].[FKColumn] AS [FKColumn]
FROM ( SELECT TOP (1) 
    [Extent1].[ColumnA] AS [ColumnA], 
    [Extent1].[ColumnB] AS [ColumnB], 
    [Extent2].[FKColumn] AS [FKColumn], 
    1 AS [C1]
    FROM  [dbo].[foreignTable] AS [Extent1]
    LEFT OUTER JOIN (SELECT 
      [Table_2].[FKColumn] AS [FKColumn], 
      [Table_2].[SomeText] AS [SomeText]
      FROM [dbo].[Table_2] AS [Table_2]) AS [Extent2] ON [Extent1].[ColumnA] = [Extent2].[FKColumn]
    WHERE [Extent1].[ColumnA] = @p__linq__7
)  AS [Limit1]

Что просто дерьмо.

Таким образом, я предполагаю, что вопрос заключается в следующем: возможно ли дать обычным Linq сущностям такое же количество SQL, как CompiledQuery?

Ответы [ 2 ]

5 голосов
/ 31 марта 2009

Запросы, которые вы сравниваете, не совпадают. Первый скомпилированный запрос возвращает одно свойство и больше ничего. Он никогда не сможет вернуть что-то другое. Второй возвращает экземпляр объекта, который вы разыменовываете, а затем получаете доступ к свойству. Когда запрос выполняется, он не может знать, что вы собираетесь просматривать только одно свойство.

Один из способов (без проверки), что вы можете получить тот же SQL из некомпилированного запроса, - проецировать в анонимный тип:

var b = (from e in entity.foreignTable.
         where ColumnA == searchForMe
         select new 
         {
            ColumnB = e.ColumnB
         }).FirstOrDefault().ColumnB;
3 голосов
/ 31 марта 2009

Скомпилированный запрос выполняет дополнительную работу, поскольку ожидается, что вы будете использовать этот запрос несколько раз. Если это то, что вам нужно, просто придерживайтесь скомпилированных запросов.

В этом конкретном сценарии вы хотите сделать:

entity.foreignTable
    .Where(x => x.ColumnA == searchForMe)
    .Select(x=>x.ColumnB)
    .FirstOrDefault();

Это не совсем то же самое, но это, безусловно, сделает запрос больше, чем вы ожидаете (только для получения ColumnB). Выполнение FirstOrDefault даст вам экземпляр, поэтому .ColumnB происходит после запроса linq2sql. Это также вызывает различия в поведении, поскольку ваша версия не будет работать из-за нулевой ссылки, в то время как этот новый запрос даст ColumnB по умолчанию (нулевое или конкретное значение в зависимости от определения ColumnB).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...