简体   繁体   English

EF Core Lazy加载非常慢

[英]EF Core Lazy loading extremely slow

I did a small test enabling lazy loading.optionsBuilder.UseLazyLoadingProxies().UseSqlServer(ConnectionString); 我做了一个小测试,以启用延迟loading.optionsBuilder.UseLazyLoadingProxies().UseSqlServer(ConnectionString);

(with EF Core 2.1.4) (使用EF Core 2.1.4)

I am looping through instruments with and without and this is the results I get 我遍历有无仪器,这就是我得到的结果

Case 1 情况1

var instruments = db.instruments.OrderBy(t=>t.id).Include(t=>t.NavPro1).ThenInclude(t=>t.NavPro2).Take(200);

Case 2 情况二

var instruments = db.instruments.OrderBy(t=>t.id).Include(t=>t.NavPro1).ThenInclude(t=>t.NavPro2).Take(200);

Then 然后

   foreach (var i in instruments)
   {
        var props = i.NavPro1;
        foreach (var prop in props)
        {
            sbPrintGreeks.AppendLine(prop.NavPro2.Name + " - " + prop.id + " - " + prop.Value);
        }
   }

Takes 7s to get 100k rows without lazy loading 花费7秒即可获得100k行,而无需延迟加载

Takes 160s to get 3k rows with lazy loading. 延迟加载需要160秒才能获得3k行。

What can be done to get decent performance ? 如何获得良好的性能?

Yes, avoid lazy loading. 是的,避免延迟加载。 Period. 期。

Problem is - always, going back to every ORM ever built - that if you do lazy loading, every reference is a lazy load. 问题是-总是回到曾经构建的每个ORM-如果您执行延迟加载,则每个引用都是延迟加载。 Which is 1+ round trips (one per property, minimum). 往返1次以上(每个住宿至少一次)。 Separate SQL execution, separate network time. 分开的SQL执行,分开的网络时间。 That adds up extremely fast. 这加起来非常快。

Which is why every ORM ever written supports NON lazy loading, in the EF variant via the .Include statements, which either extend the SQL, or generate separate SQL (ef core, tolist to materialize relationships with efficient sql). 这就是为什么以前编写的每个ORM都通过.include语句在EF变体中支持NON延迟加载的原因,该语句可以扩展SQL或生成单独的SQL(ef核心,列出以实现与有效sql的关系)。

If you insist on using lazy loading - as your question implies, there is no magic dust you spread over your code to avoid the implied negatives of lazy loading. 如果您坚持使用延迟加载-就像您的问题所暗示的那样,您不会在代码上散布任何魔术尘,从而避免了延迟加载的隐含负面影响。

Now, adding to that - any EF Core before 3.0 is as broken as it gets. 现在,添加到它-3.0之前的任何EF Core都已损坏。 And yes, that is 3.0 - not even 2.2. 是的,那是3.0-甚至是2.2。 See, there are TONS of issues with various parts, including pretty basic LINQ. 看到,各个部分都有很多问题,包括基本的LINQ。 And performance. 和性能。 At least 2.2 (coming hopefully in a month) should fix some issue. 至少2.2(希望在一个月内出现)应该可以解决一些问题。 Until then, try using .Include and AsNoTracking - because IIRC there is a performance bug that also may hit you with when loading 200k rows. 在此之前,请尝试使用.include和AsNoTracking-因为IIRC存在性能错误,在加载20万行时也可能会遇到问题。

This is a general problem that is known as the N+1 problem. 这是一个普遍的问题,称为N + 1问题。

What's happening here is that you have a lot more requests when you use lazy loading. 这里发生的是,当您使用延迟加载时,您会有更多的请求。

The case where you use Include , you have one huge request that gives you all the data - or maybe one request per table, so three request in your case. 在使用Include的情况下,您有一个巨大的请求为您提供了所有数据-或每个表一个请求,因此您的情况下为三个请求。 This depends on the exact structure of your data. 这取决于数据的确切结构。

In the case with the lazy loading, you have one request for the instruments and for each instrument you have another request for NavPro1. 在延迟加载的情况下,您对仪器有一个请求,而对于每台仪器,您都有对NavPro1的另一个请求。 And for each NavPro1 element, you have yet another request for NavPro2. 对于每个NavPro1元素,您还有另一个对NavPro2的请求。

So, if you have 1000 instruments, and each has 10 NavPro1, you now have 1 + (1000 * (1 + 10)) = 11001 requests instead of a maximum of three requests. 因此,如果您有1000台仪器,每台仪器有10台NavPro1,则现在您有1 +(1000 *(1 + 10))= 11001个请求,而不是最多三个请求。 That's slow, period. 那太慢了,期间。

https://github.com/aspnet/EntityFrameworkCore/issues/12451 https://github.com/aspnet/EntityFrameworkCore/issues/12451

This is solution 这是解决方案

services .AddDbContext(b => b.ReplaceService()); 服务.AddDbContext(b => b.ReplaceService());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM