简体   繁体   English

实体框架COUNT正在对所有记录进行SELECT

[英]Entity Framework COUNT is doing a SELECT of all records

Profiling my code because it is taking a long time to execute, it is generating a SELECT instead of a COUNT and as there are 20,000 records it is very very slow. 对我的代码进行性能分析,因为要花很长时间才能执行,它会生成SELECT而不是COUNT,并且由于有20,000条记录,因此非常慢。

This is the code: 这是代码:

var catViewModel= new CatViewModel();

var catContext = new CatEntities();

var catAccount = catContext.Account.Single(c => c.AccountId == accountId);

catViewModel.NumberOfCats = catAccount.Cats.Count();

It is straightforward stuff, but the code that the profiler is showing is: 它是简单明了的东西,但探查器显示的代码是:

exec sp_executesql N'SELECT 
[Extent1].xxxxx AS yyyyy, 
[Extent1].xxxxx AS yyyyy, 
[Extent1].xxxxx AS yyyyy, 
[Extent1].xxxxx AS yyyyy // You get the idea
FROM [dbo].[Cats] AS [Extent1]
WHERE Cats.[AccountId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=7

I've never seen this behaviour before, any ideas? 我以前从未见过这种行为,有什么想法吗?

Edit: It is fixed if I simply do this instead: 编辑:它是固定的,如果我只是这样做:

catViewModel.NumberOfRecords = catContext.Cats.Where(c => c.AccountId == accountId).Count();

I'd still like to know why the former didn't work though. 我仍然想知道为什么前者不起作用。

So you have 2 completely separate queries going on here and I think I can explain why you get different results. 因此,您在这里进行了2个完全独立的查询,我想我可以解释为什么您得到不同的结果。 Let's look at the first one 让我们看第一个

// pull a single account record
var catAccount = catContext.Account.Single(c => c.AccountId == accountId);
// count all the associated Cat records against said account
catViewModel.NumberOfCats = catAccount.Cats.Count();

Going on the assumption that Cats has a 0..* relationship with Account and assuming you are leveraging the frameworks ability to lazily load foreign tables then your first call to catAccounts.Cats is going to result in a SELECT for all the associated Cat records for that particular account. 继续假设CatsAccount之间的关系为0..* ,并假设您正在利用框架功能延迟加载外部表,然后您对catAccounts.Cats的首次调用将导致对所有与Cat相关的Cat记录进行SELECT该特定帐户。 This results in the table being brought into memory therefore the call to Count() would result in an internal check of the Count property of the in-memory collection (hence no COUNT SQL generated). 这导致表被带入内存,因此对Count()的调用将导致对内存中集合的Count属性的内部检查(因此不会生成COUNT SQL)。

The second query 第二个查询

catViewModel.NumberOfRecords = 
    catContext.Cats.Where(c => c.AccountId == accountId).Count();

Is directly against the Cats table (which would be IQueryable<T> ) therefore the only operations performed against the table are Where / Count , and both of these will be evaluated on the DB-side before execution so it's obviously a lot more efficient than the first. 直接针对Cats表(这将是IQueryable<T> ),因此对该表执行的唯一操作是Where / Count ,并且这两个操作都将在执行执行之前在DB端进行评估,因此显然效率比首先。

However, if you need both Account and Cats then I would recommend you eager load the data on the fetch, that way you take the hit upfront once 但是,如果您同时需要AccountCats那么我建议您急于将数据加载到提取中,这样您就可以先进行一次点击

var catAccount = catContext.Account.Include(a => a.Cats).Single(...);

Most times, when somebody accesses a sub-collection of an entity, it is because there are a limited number of records, and it is acceptable to populate the collection . 大多数情况下,当某人访问实体的子集合时,这是因为记录数量有限,并且可以填充该集合 Thus, when you access: 因此,当您访问:

catAccount.Cats

(regardless of what you do next), it is filling that collection . (无论您下一步要做什么),它都会填充该集合 Your .Count() is then operating on the local in-memory collection. 然后,您的.Count()将在本地内存集合上运行。 The problem is that you don't want that. 问题是您不想要那样。 Now you have two options: 现在,您有两个选择:

  • check whether your provider offer some mechanism to make that a query rather than a collection 检查您的提供者是否提供某种机制来进行查询而不是集合
  • build the query dynamically 动态建立查询
  • access the core data-model instead 而是访问核心数据模型

I'm pretty confident that if you did: 我非常有信心,如果您这样做:

catViewModel.NumberOfRecords =
    catContext.Cats.Count(c => c.AccountId == accountId);

it will work just fine. 它会很好地工作。 Less convenient? 不太方便? Sure. 当然。 But "works" is better than "convenient". 但是“作品”比“便利”要好。

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

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