Оптимизация запросов Linq2Entities + Entity Framework: .Where () против Linq, где - PullRequest
1 голос
/ 14 апреля 2011

У меня был запрос Linq к моей модели Entity Framework, который был что-то вроде:

from e1 in context.Entity1
from e2 in context.Entity2
from e3summary in
    from e3 in context.Entity3
    where e3.Field1 = value // <-- this is the line in question
    group e3 by new { e3.Field1, e3.Field2, e3.Field3 }
        into e3group
        select new
        {
            e3group.Key.Field1,
            e3group.Key.Field2,
            e3group.Key.Field3,
            Total = e3group.Sum(o => o.Field4)
        }
where
    // conditions on e1 and joining e1, e2, and e3summary
    ... 

select e1;

Сгенерированный SQL выбирал все из моей таблицы e3 (фактически, представление в базе данных) в качестве производногоtable, затем применяя предложение where к производной таблице, группируя его и объединяя с другими моими результатами.Это почти то, что я хотел, за исключением того, что я думал, что мне не нужно группировать весь вид e3 (это 73M записей в моей тестовой базе данных, почти 800M в производстве).Я ожидал, что предложение WHERE в моем запросе Linq будет применено на самом внутреннем уровне, но вместо этого я получал (я включаю только соответствующую часть):

...
INNER JOIN (SELECT
    [Extent3].[Field1] AS [K1],
    [Extent3].[Field2] AS [K2],
    [Extent3].[Field3] AS [K3],
    SUM([Extent3].Field4] AS [A1]
    FROM (SELECT
        [e3].[ID] AS [ID],
        [e3].[Field1] AS [Field1],
        [e3].[Field2] AS [Field2],
        [e3].[Field3] AS [Field3],
        [e3].[Field4] AS [Field4],
        [e3].[Field5] AS [Field5],
        [e3].[Field6] AS [Field6],
        [e3].[Field7] AS [Field7],
        [e3].[Field8] AS [Field8]
        FROM [dbo].[e3] AS [e3]) AS [Extent3]
            WHERE ([Extent3].[Field1] = @p__linq__0)
            GROUP BY [Extent3].[Field1], [Extent3].[Field2], [Extent3].[Field3] ) AS [GroupBy1]
    ...

Я изменил свой запрос Linqот

    from e3 in context.Entity3
    where e3.Field1 = value // <-- this is the line in question

до

    from e3 in context.Entity3.Where(e => e.Field1 = value)

, и это создало то, что я первоначально ожидал, предложение WHERE на самом внутреннем уровне:

        ...
        FROM [dbo].[e3] AS [e3] WHERE [e3].Field1] = @p__linq__0) AS [Extent3]
            GROUP BY [Extent3].[Field1], [Extent3].[Field2], [Extent3].[Field3] ) AS [GroupBy1]

Почему бычем разница между применением .Where([condition]) непосредственно к коллекции в моем контексте и наличием where [condition] в моем запросе Linq?Я бы подумал, что это будет разбираться в дереве выражений таким же образом.

PS В sidenote, помещая оба запроса в SQL Server Management Studio и сравнивая план выполнения запроса, я был удивлен, обнаружив, что план выполнения былточно так же в любом случае.Оптимизатор плана запросов SQL действительно невероятен!

1 Ответ

3 голосов
/ 14 апреля 2011

Разница между этими запросами заключается в представлении используемых вами конструкций. Первый запрос оценивается как

 (from e3 in context.Entity3) where e3.Fied1 == value

, тогда как второй запрос оценивается как

 from e3 in (context.Entity3.Where(e => e.Field1 == value))

Пунктирный синтаксис имеет приоритет, потому что он рассматривается как отдельное поддерево выражения, которое должно быть построено и присоединено к дереву выражений внешнего запроса. Вы можете думать об этом как о подзапросе, даже если он не должен быть подзапросом в конце, как показано в вашем примере.

...