【问题标题】:Why is Entity Framework taking 30 seconds to load records when the generated query only takes 1/2 of a second?当生成的查询只需要 1/2 秒时,为什么 Entity Framework 需要 30 秒来加载记录?
【发布时间】:2009-03-26 16:33:33
【问题描述】:

下面的executeTime是第一次30秒,下次我执行同一组代码时是25秒。在 SQL Profiler 中观看时,我立即看到一个登录名,然后它就在那里停留了大约 30 秒。然后,只要运行 select 语句,应用程序就会完成 ToList 命令。当我从 Management Studio 运行生成的查询时,数据库查询只需要大约 400 毫秒。它返回 14 行和 350 列。看起来将数据库结果转换为实体所需的时间非常短,以至于不会引起注意。

那么在调用数据库之前的 30 秒内发生了什么?

如果实体框架这么慢,我们就无法使用它。有什么我做错了,或者我可以改变什么来显着加快速度吗?

更新: 好吧,如果我使用 Compiled 查询,第一次需要 30 秒,第二次需要 1/4 秒。有什么办法可以加快第一次通话的速度吗?

using (EntitiesContext context = new EntitiesContext()) 
{ 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
    var groupQuery = (from g in context.Groups.Include("DealContract") 
                    .Include("DealContract.Contracts") 
                    .Include("DealContract.Contracts.AdvertiserAccountType1") 
                    .Include("DealContract.Contracts.ContractItemDetails") 
                    .Include("DealContract.Contracts.Brands") 
                    .Include("DealContract.Contracts.Agencies") 
                    .Include("DealContract.Contracts.AdvertiserAccountType2") 
                    .Include("DealContract.Contracts.ContractProductLinks.Products") 
                    .Include("DealContract.Contracts.ContractPersonnelLinks") 
                    .Include("DealContract.Contracts.ContractSpotOrderTypes") 
                    .Include("DealContract.Contracts.Advertisers") 
                where g.GroupKey == 6 
                select g).OfType<Deal>(); 
    sw.Stop(); 
    var queryTime = sw.Elapsed; 
    sw.Reset(); 
    sw.Start(); 
    var groups = groupQuery.ToList(); 
    sw.Stop(); 
    var executeTime = sw.Elapsed; 
} 

【问题讨论】:

    标签: c# .net entity-framework linq-to-entities


    【解决方案1】:

    我遇到了同样的问题,我的查询需要 40 秒。

    我发现问题出在.Include("table_name") 函数上。我拥有的越多,情况就越糟。相反,我将我的代码更改为在查询后立即延迟加载我需要的所有数据,这将总时间从 40 秒减少到大约 1.5 秒。据我所知,这完成了完全相同的事情。

    所以对于您的代码,它会是这样的:

    var groupQuery = (from g in context.Groups
                where g.GroupKey == 6 
                select g).OfType<Deal>(); 
    
    var groups = groupQuery.ToList();
    
    foreach (var g in groups)
    {
        // Assuming Dealcontract is an Object, not a Collection of Objects
        g.DealContractReference.Load();
        if (g.DealContract != null)
        {
            foreach (var d in g.DealContract)
            {
                // If the Reference is to a collection, you can just to a Straight ".Load"
                //  if it is an object, you call ".Load" on the refence instead like with "g.DealContractReference" above
                d.Contracts.Load();
                foreach (var c in d.Contracts)
                {
                    c.AdvertiserAccountType1Reference.Load();
                    // etc....
                }
            }
        }
    }
    

    顺便说一句,如果您要在当前代码的查询上方添加这行代码,它会将时间缩短到大约 4-5 秒(我的选择仍然太长)据我了解,@987654324 @ 选项禁用了大量用于更新和将内容插入数据库的跟踪开销:

    context.groups.MergeOption = MergeOption.NoTracking;
    

    【讨论】:

    • 这看起来很反直觉。发出多个 SQL 请求并加载相同数量的对象比发出一个 sql 请求更快吗?
    • 克里斯,你似乎对 .include 了解很多,你能看看我的帖子吗stackoverflow.com/questions/10320174/…
    • @bugz - 我看了看。对不起,伙计,我不知道。我应该注意到,最后我对 ASP.net 和实体框架非常不满意。我所做的一切都花费了太长时间。我目前正在用谷歌应用引擎重写整个应用程序。
    • 黄金。除了最简单的情况外,包含似乎对所有情况都是纯粹的邪恶
    【解决方案2】:

    这是因为包含。我的猜测是您急于将大量对象加载到内存中。构建与您的数据库实体相对应的 c# 对象需要很长时间。

    我对您的建议是尝试仅延迟加载您需要的数据。

    【讨论】:

    • 延迟加载无济于事,因为我们需要包含所有对象。它实际上只返回总共大约 40 个对象(1 个交易、3 个 DealContracts、3 个合同、每个合同上的 3 个 contractitemdetails 以及每个合同上的每个其他属性中的 1 个),所以我认为它不会太密集......?
    • 我不同意需要所有对象意味着延迟加载无济于事。原因见我的回答。有时执行一个更简单的查询然后让其他更简单的查询的细节更快。
    【解决方案3】:

    据我所知,使查询的初始编译更快的唯一方法是使查询不那么复杂。 performance considerations for the Entity FrameworkCompiled Queries 上的 MSDN 文档并未表明有任何方法可以保存已编译的查询以在不同的应用程序执行会话中使用。

    我要补充一点,我们发现拥有大量包含可以使查询执行比拥有更少的包含和稍后在相关实体上执行更多加载更慢。需要反复试验才能找到合适的媒介。

    但是,我不得不问一下,您是否真的需要这里包含的每个实体的所有属性。在我看来,这个查询中有大量不同的实体类型,因此实现它们可能会非常昂贵。如果您只是想获得您不打算更新的表格结果,那么出于各种原因,将您实际需要的(相对)较少数量的字段投影到平面匿名类型中应该会明显更快。此外,这让您不必担心急切加载、调用 Load/IsLoaded 等。

    您当然可以通过预编译实体视图来加快初始视图的生成。有documentation on MSDN for this。但是由于您在执行第一个查询时支付了该费用,因此您对简单查询的测试表明,这对您来说运行时间约为 2 秒。说 2 秒很好,但它不会保存任何其他内容。

    【讨论】:

    • 不幸的是,我确实需要所有对象的所有属性。
    【解决方案4】:

    EF 需要一段时间才能启动。它需要从 xml 构建元数据,并可能生成用于映射的对象。 所以启动需要几秒钟,我认为没有办法解决这个问题,除非永远不要重新启动你的程序。

    【讨论】:

    • 真的,启动需要30秒?这似乎太过分了。
    • 我并没有真正将它用于任何复杂的模型,并且大多数时间启动大约需要 5 秒。您的对象看起来比我拥有的对象复杂得多。尝试做一个较小的查询,看看需要多长时间。
    • 在复杂查询之前添加一个简单查询(1条记录,不包含)节省2秒。所以它似乎需要 EF 2 秒才能启动。第一个太长的复杂查询仍然需要 28 秒。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-29
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多