实体框架顺序是否有差异?



>我在项目中遇到了一些速度问题,这似乎是它使用实体框架调用数据库的主要原因。每次调用数据库时,它总是按database.Include(...).Where(...)我想知道这是否与database.Where(...).Include(...)

我的想法是,第一种方法包括目标表中所有元素的所有内容,然后过滤掉我想要的元素,而第二种方法过滤掉我想要的元素,然后只包含这些元素的所有内容。我不完全了解实体框架,所以我的想法正确吗?

实体框架尽可能长时间地延迟其查询,直到代码开始处理数据为止。只是为了证明这个例子:

var query = db.People
.Include(p => p.Cars)
.Where(p => p.Employer.Name == "Globodyne")
.Select(p => p.Employer.Founder.Cars);

对于所有这些链式调用,EF 尚未调用数据库。相反,它会跟踪您尝试获取的内容,并且它知道如果您开始使用数据运行哪个查询。如果在此之后再也不对query执行任何其他操作,那么您将永远不会访问数据库。

但是,如果您执行以下任一操作:

var result = query.ToList();
var firstCar = query.FirstOrDefault();
var founderHasCars = query.Any();

现在,EF被迫查看数据库,因为它无法回答您的问题,除非它实际从数据库中获取数据。此时,而不是之前,EF 是否实际命中数据库。

作为参考,这个用于获取数据的触发器通常称为"枚举集合",即将查询转换为实际的结果集。

通过尽可能长时间地延迟该查询的执行,EF 能够等待并查看是否要筛选/排序/分页/转换/...结果集,这可能导致 EF 需要返回的数据少于立即执行每个命令时返回的数据。


这也意味着,当您调用Include时,您实际上并没有命中数据库,因此如果您没有枚举集合,您将不会从稍后将由Where子句过滤的项目中加载数据。

举这两个例子:

var list1 = db.People
.Include(p => p.Cars)
.ToList()                     // <= enumeration
.Where(p => p.Name == "Bob");
var list2 = db.People
.Include(p => p.Cars)
.Where(p => p.Name == "Bob")
.ToList();                    // <= enumeration

这些列表最终将产生相同的结果。但是,第一个列表将在您过滤数据之前获取数据,因为您在Where之前调用了ToList。这意味着您将在内存中加载所有人及其汽车,然后在内存中过滤该列表。

但是,第二个列表仅在已知Where子句时枚举集合,因此 EF 只会将名为 Bob 的人及其汽车加载到内存中。筛选将在数据库发送回运行时之前在数据库上进行。


您没有显示足够的代码让我验证您是否过早枚举集合。我希望这个答案可以帮助您确定这是否是性能问题的原因。

database.Include(...).Where(...),我想知道这是否与database.Where(...).Include(...)不同?

假设此代码是逐字的(缺少的数据库集除外(,并且在IncludeWhere之间没有任何反应,则订单不会更改执行,因此它不是性能问题的根源。

我通常建议您将Include语句放在其他任何内容之前(即紧接在db.MyTable之后(,作为可读性的问题。其他操作取决于您尝试构造的特定查询。

大多数时候,子句的顺序不会有任何区别Include语句告诉 SQL 一个表与另一个表Join虽然Where将导致..是的,SQLWhere

当你做类似database.Include(...).Where(...)的事情时,你正在构建IQueryable对象,当你尝试像.ToList().FirstOrDefault()一样访问它并且这些查询已经优化后,该对象将被转换为直接SQL

因此,如果仍然存在性能问题 - 应使用探查器查找瓶颈,并可能考虑使用存储过程(这些存储过程可以与 EF 集成(

相关内容

最新更新