2017-04-24 56 views
0

我有一个非常奇怪的问题,那就是我的LINQ查询执行得太慢。代码如下:甚至对于小集合,LINQ查询执行得非常缓慢

var user = ctx.Users.FirstOrDefault(x => x.Username== username); 

ViewBag.Items = user.Items.GroupBy(x => x.ItemId).Select(pr => new SalesViewModel 
{ 
ImageURL = pr.Select(x=>x.ImageURL).FirstOrDefault(), 
Title= pr.Select(x=>x.Title).FirstOrDefault(), 
Sales = pr.Select(x=>x.Transactions.Sum(y=>y.QuantitySold)).FirstOrDefault() 
}) 
.OrderByDescending(x=>x.Sales) 
.ToList(); 

所以用户对象包含一个ICollection集合包含1300个项目的项目。并且每个这些项目包含另一个ICollection被称为“交易”收集...

我注意到,这些每个都有最多20-25个交易,所以项目内的集合不是那么大...

我在这里做错了什么,为什么LINQ需要30-40秒来处理这段代码?

有没有什么办法让它更好?

+0

由该集团是没有必要的,如果'ItemId'是Items'表 – octavioccl

+0

的'的PK @octavioccl这不是遗憾的是:(...这是一个单独的属性 – User987

+1

I'n从'ctx'猜测这是实体的linq?如果是这样,使用一个分析器来查看正在生成什么SQL语句 – stuartd

回答

0

请改变你的LINQ查询到:

var user = ctx.Users.FirstOrDefault(x => x.Username== username); 

ViewBag.Items = user.Items.GroupBy(x => x.ItemId).Select(pr => new SalesViewModel 
{ 
    ImageURL = pr.FirstOrDefault(x=>x.ImageURL), 
    Title= pr.FirstOrDefault(x=>x.Title), 
    Sales = pr.FirstOrDefault(x=>x.Transactions.Sum(y=>y.QuantitySold)) 
}) 
.OrderByDescending(x=>x.Sales) 
.ToList(); 
+1

Muhammad,当您按ItemID进行分组时,您如何实际访问ImageURL/TItle/Transactions属性? – User987

+3

'pr'是一个组,不是'Item' – octavioccl

+0

请参阅我的更新回答:) –

0

试试这个办法:

var ids = user.Items 
    .GroupBy(x => x.ItemId) 
    .Where(x=> x.Any()) 
    .Select(pr => pr.First().Id); /* No ToList yet */ 

user 
    .Items 
    .Where(x=> ids.Contains(x.Id)) // <-- 
    .Select(pr => new SalesViewModel 
    { 
     ImageURL = x.ImageURL, 
     Title= x.Title, 
     Sales = x.Transactions.Sum(y=>y.QuantitySold) 
    }) 
    .ToList(); 

的方法是,从昂贵的GroupBy读的主键,把它作为一个子查询为主查询。尝试在LINQPad或SSMS中查看这是否有所作为。

+0

它说当前上下文中不存在.select? – User987

+0

@ User987对不起,我更新了答案,第一个查询现在有一个额外的'Where'并更新了'Select' – undefined

+0

由于某种原因,它仍然表示选择不存在于当前上下文中:D – User987

0

正如Ivan Stoev在评论中写道,它应该是由延迟加载导致的N + 1查询问题。这里的答案是在总结事务之前使用include语句并加载子实体。

var user = ctx.Users.FirstOrDefault(x => x.Username== username).Include("Items").Include("Transactions");