C# 实体框架计数正在对所有记录进行选择
分析我的代码,因为它需要很长时间来执行,它生成的是一个SELECT而不是计数,并且由于有20000条记录,所以速度非常慢 代码如下:C# 实体框架计数正在对所有记录进行选择,c#,entity-framework,C#,Entity Framework,分析我的代码,因为它需要很长时间来执行,它生成的是一个SELECT而不是计数,并且由于有20000条记录,所以速度非常慢 代码如下: var catViewModel= new CatViewModel(); var catContext = new CatEntities(); var catAccount = catContext.Account.Single(c => c.AccountId == accountId); catViewModel.NumberOfCats =
var catViewModel= new CatViewModel();
var catContext = new CatEntities();
var catAccount = catContext.Account.Single(c => c.AccountId == accountId);
catViewModel.NumberOfCats = catAccount.Cats.Count();
这很简单,但分析器显示的代码是:
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
我以前从未见过这种行为,有什么想法吗
编辑:如果我只是这样做,它是固定的:
catViewModel.NumberOfRecords=catContext.Cats.Where(c=>c.AccountId==AccountId.Count()代码>
我仍然想知道为什么前者不起作用。大多数情况下,当有人访问实体的子集合时,这是因为记录数量有限,并且可以填充集合。因此,当您访问:
catAccount.Cats
(不管你下一步做什么),它都在填充该集合。然后,您的.Count()
正在本地内存中集合上运行。问题是你不想那样。现在您有两个选择:
- 检查您的提供者是否提供了某种机制使其成为查询而不是集合
- 动态构建查询
- 改为访问核心数据模型
我很有信心,如果你做到了:
catViewModel.NumberOfRecords =
catContext.Cats.Count(c => c.AccountId == accountId);
它会很好用的。不太方便?当然但是“工作”比“方便”好。大多数情况下,当有人访问实体的子集合时,这是因为记录数量有限,并且可以填充集合。因此,当您访问:
catAccount.Cats
(不管你下一步做什么),它都在填充该集合。然后,您的.Count()
正在本地内存中集合上运行。问题是你不想那样。现在您有两个选择:
- 检查您的提供者是否提供了某种机制使其成为查询而不是集合
- 动态构建查询
- 改为访问核心数据模型
我很有信心,如果你做到了:
catViewModel.NumberOfRecords =
catContext.Cats.Count(c => c.AccountId == accountId);
它会很好用的。不太方便?当然但是“有效”比“方便”好。所以这里有两个完全不同的查询,我想我可以解释为什么会得到不同的结果。让我们看看第一个
// 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();
假设Cats
与Account
有0..*
关系,并且假设您正在利用框架功能惰性加载外部表,那么您第一次调用catAccounts.Cats
将导致对所有相关的Cat
记录进行选择那个特别的账户。这将导致表被带到内存中,因此对Count()
的调用将导致对内存集合的Count
属性进行内部检查(因此不会生成Count
SQL)
第二个问题
catViewModel.NumberOfRecords =
catContext.Cats.Where(c => c.AccountId == accountId).Count();
直接针对Cats
表(该表将是IQueryable
),因此对该表执行的唯一操作是,其中
/计数
,这两个操作都将在执行前在DB端进行评估,因此显然比第一个更有效
但是,如果您同时需要Account
和Cats
,那么我建议您立即将数据加载到fetch中,这样您就可以预先命中一次
var catAccount = catContext.Account.Include(a => a.Cats).Single(...);
这里有两个完全不同的查询,我想我可以解释为什么会得到不同的结果。让我们看看第一个
// 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();
假设Cats
与Account
有0..*
关系,并且假设您正在利用框架功能惰性加载外部表,那么您第一次调用catAccounts.Cats
将导致对所有相关的Cat
记录进行选择那个特别的账户。这将导致表被带到内存中,因此对Count()
的调用将导致对内存集合的Count
属性进行内部检查(因此不会生成Count
SQL)
第二个问题
catViewModel.NumberOfRecords =
catContext.Cats.Where(c => c.AccountId == accountId).Count();
直接针对Cats
表(该表将是IQueryable
),因此对该表执行的唯一操作是,其中
/计数
,这两个操作都将在执行前在DB端进行评估,因此显然比第一个更有效
但是,如果您同时需要Account
和Cats
,那么我建议您立即将数据加载到fetch中,这样您就可以预先命中一次
var catAccount = catContext.Account.Include(a => a.Cats).Single(...);
这看起来像是对Single
的调用。对Single的调用生成:exec sp_executesql N'SELECT TOP(2)XXX作为YYY,(等)FROM[dbo]。[Account]作为[Extent1],其中[Extent1]。[AccountId]=@p_ulinq_u0',N'@p_ulinq_u0 int',@p_uulinq_uu0=7
Single
立即收回一条记录。catAccount.Cats
如何声明?指向数据库并按“go”生成模型的标准。从Daniel上面的评论来看,虽然我猜测Single的即时性是问题的原因,但似乎EF可能会在那之后放弃聪明……对我来说,这看起来像是对Single
的调用。调用Single生成:exec sp_executesql N'SELECT TOP(2)XXX作为yyyy,(等)From[dbo].[Account]作为[Extent1],其中[Extent1]。[帐户ID]=@p_uulinq_u0',N'@p_ulinq_u0 int',@p_ulinq_u0=7
Single
立即收回一条记录。catAccount.Cats
是如何声明的?标准指向数据库并按“go”生成模型。尽管我猜测Single的即时性是问题的原因,但从Daniel的上述评论来看,EF可能会在那之后,我开始变得聪明起来。。。