当生成的查询只需要1/2秒时,为什么Entity Framework需要30秒才能加载记录?

.net c# entity-framework linq-to-entities

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

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

如果实体框架这么慢,我们就不可能使用它。有什么我做错了或者我可以改变什么来加速这一点吗?

更新:好吧,如果我使用编译查询,第一次需要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; 
} 

一般承认的答案

我有同样的问题,我的查询需要40秒。

我发现问题出在.Include("table_name")函数上。我拥有的越多,它就越糟糕。相反,我在查询后立即将我的代码更改为Lazy Load所需的所有数据,这将总时间从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秒(在我的选项中仍然过于MergeOption.NoTracking )从我的理解, MergeOption.NoTracking选项禁用更新和插入数据库的大量跟踪开销:

context.groups.MergeOption = MergeOption.NoTracking;

热门答案

这是因为包括。我的猜测是你渴望将大量对象加载到内存中。构建与db实体对应的c#对象需要花费很多时间。

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




许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因