分析我的代码,因为它需要很长时间才能执行,它生成一个SELECT而不是COUNT,因为有20,000条记录,它非常慢。
这是代码:
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();
我仍然想知道前者为什么不起作用。
答案 0 :(得分:4)
所以你在这里有2个完全独立的查询,我想我可以解释为什么你会得到不同的结果。我们来看看第一个
// 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
与0..*
之间存在Account
关系并假设您正在利用框架功能懒洋洋地加载外表,那么您首次调用catAccounts.Cats
将为该特定帐户的所有关联SELECT
记录生成Cat
。这导致表被带入内存,因此对Count()
的调用将导致对内存中集合的Count
属性进行内部检查(因此不生成COUNT
SQL。
第二个查询
catViewModel.NumberOfRecords =
catContext.Cats.Where(c => c.AccountId == accountId).Count();
直接针对Cats
表(可能是IQueryable<T>
),因此针对该表执行的唯一操作是Where
/ Count
,这两个操作都将是在执行之前在DB端进行评估,因此它显然比第一个更有效。
但是,如果您同时需要Account
和Cats
,那么我建议您急切地在抓取时加载数据,这样您就可以提前点击
var catAccount = catContext.Account.Include(a => a.Cats).Single(...);
答案 1 :(得分:2)
大多数情况下,当有人访问实体的子集合时,这是因为记录数量有限,填充集合是可以接受的。因此,当您访问:
catAccount.Cats
(无论你接下来做什么),填充该集合。然后,您的.Count()
将在本地内存中集合上运行。问题是你不想要那个。现在您有两个选择:
如果你这样做,我非常有信心:
catViewModel.NumberOfRecords =
catContext.Cats.Count(c => c.AccountId == accountId);
它会正常工作。不太方便?当然。但是&#34;工作&#34;优于&#34;方便&#34;。