简体   繁体   English

实体框架计数效率

[英]Entity Framework Count Efficiency

I query the school entity from the database. 我从数据库查询学校实体。 And then, I try to get the number of students in that school by doing this: 然后,我尝试通过这样做来获得那所学校的学生人数:

var school = context.schools.Where(s=>s.ID == 1).Single();
int cnt = school.students.Count();

But I see that the query sent to database gets all the student records in that school, and the counting is done on the application server. 但是我看到发送到数据库的查询获取了该学校的所有学生记录,并且计数是在应用程序服务器上完成的。

Whereas the following just queries the COUNT() from the database, as it should be: 而下面的内容只是从数据库中查询COUNT():

int cnt = context.students.Where(s=>s.schoolID == 1).Count();

Why is there such a difference between these two approaches? 为什么这两种方法之间有如此不同? Shouldn't the first query also use COUNT() to be efficient? 第一个查询是否也应该使用COUNT()来提高效率?

Note: Not querying the school entity is not an option because I am using some of its fields. 注意:不查询学校实体不是一种选择,因为我正在使用它的某些字段。

school.students.Count() working via LazyLoading , so at first, you fetch students: school.students and then .Count() them on client side, as you already wrote. school.students.Count()通过惰性加载工作,所以在第一次,你取的学生: school.students然后.Count()他们在客户端,因为你已经写了。 But you can modify your code the way, which will perform one trip to database: 但是您可以按照以下方式修改代码,这将执行一次数据库访问:

var answer = (from sch in context.schools
              where sch.ID == 1
              join st in context.students on sch.ID equals st.schoolID into subs
              from sub in subs.DefaultIfEmpty()
              group sub by new { sch.ID, sch.Name, sch.Location } into gr
              select new 
              {
                  gr.Key.Name,
                  gr.Key.Location,
                  Count = gr.Count(x => x != null)
              }).First();

sch.Name , sch.Location - school's fields, which you need for further use sch.Namesch.Location学校的字段,您需要进一步使用

Queries are run at the last possible moment to make them as efficient as possible - called Lazy Loading - and in your first example your Single() call forces the data provider to be less lazy than you might like. 在尽可能最后的时刻运行查询,以使其尽可能高效-称为“延迟加载”-在第一个示例中,您的Single()调用迫使数据提供者的延迟不如您所愿。

When you call Single() , you're asking for an entire Student record - the first in the list of all student records, so the query has to run ( GET SchoolId, SchoolName, .... FROM SCHOOLS WHERE SchoolId = 1 ) to get you that data. 调用Single() ,您要索取完整的Student记录-所有学生记录列表中的第一条记录,因此必须运行查询( GET SchoolId, SchoolName, .... FROM SCHOOLS WHERE SchoolId = 1 )为您获取数据。 Then afterwards you call Count() , replaying the query except only selecting COUNT . 然后,您调用Count() ,重播查询,只选择COUNT

Instead in your second example, you call Count() only after a Where() call. 而是在第二个示例中,仅在Where()调用之后才调用Count() Where() doesn't force the query to play because you haven't accessed any data yet, so the data provider can smartly only play a GET COUNT - type query on the database after it evaluates Count() . Where()不会强制查询播放,因为您尚未访问任何数据,因此数据提供者在对Count()求值后,只能聪明地在数据库上播放GET COUNT类型的查询。

How to tell if a LINQ method will 'play' your query? 如何判断LINQ方法是否会“播放”您的查询? The way I remember is that if it returns IQueryable<T> it will not play your query, anything else, it will. 我记得的方式是,如果它返回IQueryable<T> ,它将不会播放您的查询,否则它将播放。

It's all about the lazy loading, but the effect is two-fold: 都是关于延迟加载的,但是效果是双重的:

  1. context.schools.Where(s=>s.ID == 1).Single() will return a school entity without any students loaded (lazy loading part 1). context.schools.Where(s=>s.ID == 1).Single()将返回未加载任何学生的学校实体(延迟加载第1部分)。 But, 但,
  2. school.students.Count() has to hit the database for all students because of the .students part - since they were not loaded in on the first line, they will be all be loaded in (because you implicitly asked for that - lazy loading part 2) then the Count() fires. 由于.students部分, school.students.Count()必须访问所有学生的数据库-由于未在第一行加载他们,因此将全部加载他们(因为您暗中要求-延迟加载)第2部分), 然后触发Count()

To cut down on the calls, either do as you suggested: int cnt = context.students.Where(s=>s.schoolID == 1).Count(); 若要减少通话,请按照您的建议进行操作: int cnt = context.students.Where(s=>s.schoolID == 1).Count(); which will result in 2 db calls, or create a grouped result as in the original answer 这将导致2个数据库调用,或按照原始答案创建分组结果

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

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