【问题标题】:How to optimize Entity Framework Queries如何优化实体框架查询
【发布时间】:2009-08-05 13:23:42
【问题描述】:

我正在使用 Linq-To-Entities 进行查询,该查询仅返回 947 行,但运行时间为 18 秒。我已经做了一个“ToTraceString”来获取底层 sql 并直接在数据库上运行相同的东西并获得相同的时间。

我使用了调优顾问并创建了几个索引,但影响不大。

查看查询执行计划,有几个嵌套循环占用了 95% 的时间,但它们已经在处理索引?

有人对如何强制对 EF 查询进行一些优化有任何想法吗?

编辑:提供更多信息

三个表的基本 ER 图如下:

People >----People_Event_Link ----< Events
P_ID        P_ID                    E_ID
            E_ID

我正在运行的 linq 旨在获取特定人员的所有事件(使用 P_ID):

        var query = from ev in genesisContext.Events
                    join pe in genesisContext.People_Event_Link
                    on ev equals pe.Event
                    where pe.P_ID == key
                    select ev;
        return query;

这是生成的 SQL(深呼吸!):

SELECT 
1 AS [C1], 
[Extent1].[E_ID] AS [E_ID], 
[Extent1].[E_START_DATE] AS [E_START_DATE], 
[Extent1].[E_END_DATE] AS [E_END_DATE], 
[Extent1].[E_COMMENTS] AS [E_COMMENTS], 
[Extent1].[E_DATE_ADDED] AS [E_DATE_ADDED], 
[Extent1].[E_RECORDED_BY] AS [E_RECORDED_BY], 
[Extent1].[E_DATE_UPDATED] AS [E_DATE_UPDATED], 
[Extent1].[E_UPDATED_BY] AS [E_UPDATED_BY], 
[Extent1].[ET_ID] AS [ET_ID], 
[Extent1].[L_ID] AS [L_ID]
FROM  [dbo].[Events] AS [Extent1]
INNER JOIN [dbo].[People_Event_Link] AS [Extent2] ON  EXISTS (SELECT 
    1 AS [C1]
    FROM    ( SELECT 1 AS X ) AS [SingleRowTable1]
    LEFT OUTER JOIN  (SELECT 
        [Extent3].[E_ID] AS [E_ID]
        FROM [dbo].[Events] AS [Extent3]
        WHERE [Extent2].[E_ID] = [Extent3].[E_ID] ) AS [Project1] ON 1 = 1
    LEFT OUTER JOIN  (SELECT 
        [Extent4].[E_ID] AS [E_ID]
        FROM [dbo].[Events] AS [Extent4]
        WHERE [Extent2].[E_ID] = [Extent4].[E_ID] ) AS [Project2] ON 1 = 1
    WHERE ([Extent1].[E_ID] = [Project1].[E_ID]) OR (([Extent1].[E_ID] IS NULL) AND ([Project2].[E_ID] IS NULL))
)
WHERE [Extent2].[P_ID] = 291

【问题讨论】:

  • 我刚刚敲了自己的 sql 来进行查询,它在不到一秒钟的时间内就运行了,哎呀.... SELECT * FROM Events AS E INNER JOIN People_Event_Link AS PE ON E.E_ID =PE.E_ID INNER JOIN PEOPLE AS P ON P.P_ID=PE.P_ID WHERE P.P_ID = 291

标签: mysql performance entity-framework


【解决方案1】:

是的。重写 LINQ 查询。大多数 LINQ to Entities 查询可以用许多不同的方式编写,并且会以不同的方式转换为 SQL。由于您既没有显示 LINQ,也没有显示 SQL,也没有显示查询计划,所以我只能说这些。

不过,您很聪明,可以尝试直接执行 SQL。查询编译也可能需要时间,但您已通过确定 SQL 占所有测量时间来排除这种情况。

试试:

    var query = from pe in genesisContext.People_Event_Link
                where pe.P_ID == key
                from ev in pe.Event // presuming one to many
                select ev;

或者如果 pe.Event 是一对一的:

    var query = from pe in genesisContext.People_Event_Link
                where pe.P_ID == key
                select pe.Event;

    return query;

【讨论】:

  • 好吧,我已经查看了 linq 查询,但老实说,它并没有太多需要更改的地方(见上文)!
  • 在 LINQ to Entities 中使用 join 几乎是不正确的。 People_Event_Link 的 Event 上的属性名称是什么(换句话说,pe.Event 的另一端?我会猜测我的答案;如果我错了,请纠正我。
【解决方案2】:

由于 95% 的时间都在嵌套循环中,消除它们应该可以解决问题。

你可以看看以下几点:

  • 是否需要嵌套循环。如果您直接在 SQL 中编写查询,您是否可以在不使用嵌套循环的情况下获得相同的结果。如果这个问题的答案是它可以在没有嵌套循环的情况下编写,那么它在模型或导致它的 linq 查询中是什么。

  • 您是否可以选择将一些逻辑放在视图中,从而降低 linq 查询的复杂性,并且可能不再需要嵌套循环。

通常我使用 SQL 服务器分析器来查看 SQL linq 生成的内容,我发现这更容易,尤其是如果您有两个屏幕。

如果您仍有问题,请发布您的 linq 查询。

【讨论】:

    【解决方案3】:

    @克雷格 我收到一条错误消息,提示在对 SelectMany 的调用中类型推断失败。

    不过,我采纳了您的建议,从使用连接转为使用“旧式”前 ANSI 类型查询:

            var query = from pe in genesisContext.People_Event_Link
                        from ev in genesisContext.Events
                        where pe.P_ID == key && pe.Event == ev
                        select ev;
    

    这会产生相当不错的 sql!

    【讨论】:

    • “对 SelectMany 的调用中类型推断失败”意味着我猜错了属性名称。但是您已经有了大致的想法——要获得不同的 SQL,请尝试不同的 LINQ。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多