在查询需要稍后在代码中访问导航属性的大型表时(我明确地不想使用延迟加载)什么会更好地执行.Include()
或.Load()
?或者为什么要使用另一个?
在这个例子中,所包含的表只有大约10个条目,员工大约有200个条目,并且可能会发生大多数条目,因为它们与where子句匹配,因此无论如何都会加载include。
Context.Measurements.Include(m => m.Product)
.Include(m => m.ProductVersion)
.Include(m => m.Line)
.Include(m => m.MeasureEmployee)
.Include(m => m.MeasurementType)
.Where(m => m.MeasurementTime >= DateTime.Now.AddDays(-1))
.ToList();
或
Context.Products.Load();
Context.ProductVersions.Load();
Context.Lines.Load();
Context.Employees.Load();
Context.MeasurementType.Load();
Context.Measurements.Where(m => m.MeasurementTime >= DateTime.Now.AddDays(-1))
.ToList();
答案 0 :(得分:78)
使用Include()
时,您可以通过一次调用底层数据存储来加载所有数据的好处。例如,如果这是一个远程SQL Server,那么这可能是一个重大的性能提升。
缺点是Include()
查询往往非常 复杂,尤其是如果您有任何过滤器({{1例如,调用)或尝试进行任何分组。 EF将使用子Where()
和SELECT
语句生成非常大量嵌套的查询,以获取所需的数据。它的效率也低得多 - 你可以在其中找到包含每个可能的子对象列的单行数据,因此顶级对象的数据将重复很多次。 (例如,具有10个子节点的单个父对象将产生10行,每个行具有父对象列的相同数据。)我有单个 EF查询变得如此复杂,导致死锁与EF更新逻辑同时运行。
APPLY
方法非常简单。每个查询都是针对单个表的单个,简单,直接的Load()
语句。这些更容易以各种可能的方式,除了你必须做很多(可能是很多次)。如果您有嵌套的集合集合,您甚至可能需要遍历顶级对象并SELECT
其子对象。它可能会失控。
尝试避免在单个查询中进行超过三次Load
次调用。我发现EF的查询过于丑陋而无法识别;它也符合我对SQL Server查询的经验法则,单个查询中最多四个JOIN语句非常有效,但之后考虑重构。
然而,所有这些只是一个起点。
这取决于您的架构,您的环境,数据以及许多其他因素。
最后,您只需要以各种方式尝试。
选择一个合理的“默认”模式,看看它是否足够好,如果没有,请优化品尝。
答案 1 :(得分:20)
Include()
将以JOIN
的形式写入SQL:一个数据库往返。
每条Load()
- 指令“显式加载”所请求的实体,因此每次调用一次数据库往返。
因此Include()
很可能是这种情况下更明智的选择,但它取决于数据库布局,调用此代码的频率以及DbContext
生存的时间。为什么不尝试两种方式并分析查询并比较时间?
答案 2 :(得分:9)
我同意他的answer中的@MichaelEdenfield,但我确实想对嵌套馆藏场景发表评论。你可以通过内部调查来解决嵌套循环(以及对数据库产生的许多调用)。
不是通过Customer的Orders集合循环,然后通过Order的OrderItems集合执行另一个嵌套循环,而是直接使用过滤器查询OrderItems,如下所示。
context.OrderItems.Where(x => x.Order.CustomerId == customerId);
您将获得与嵌套循环中的Loads相同的结果数据,但只需调用一次数据库。
此外,还有一个特殊情况应考虑包含。如果父对象与子对象之间的关系是一对一的话,那么多次返回父数据的问题就不会成为问题。
我不确定如果大部分案例都没有孩子存在会产生什么影响 - 很多空?一对一关系中的稀疏孩子可能更适合我上面概述的直接查询技术。
答案 3 :(得分:5)
Include
是一个热切加载的示例,您不仅要加载要查询的实体,还要加载所有相关实体。
Load
是EnableLazyLoading
的手动覆盖。如果此项设置为false
。您仍然可以通过.Load()
答案 4 :(得分:1)
总是很难决定是否选择Eager,Explicit甚至Lazy Loading
无论如何,我建议总是进行一些分析。这是确保您的请求具有高效性的唯一方法
有很多工具可以帮助你。看看this article from Julie Lerman,其中列出了几种不同的分析方法。一个简单的解决方案是启动profiling in your SQL Server Management Studio
不要犹豫与DBA(如果您在附近)谈话,这将有助于您了解执行计划。
您还可以查看this presentation,其中我写了一个关于加载数据和性能的部分。
答案 5 :(得分:1)
要添加到此主题还有一件事。这取决于您使用的服务器。如果您正在使用sql server,则可以使用预先加载但是对于sqlite,您必须使用.Load()来避免交叉加载异常,因为sqlite无法处理一些比一个依赖级更深的include语句