简体   繁体   English

低效的实体框架查询

[英]Inefficient entity framework queries

I have a following foreach statement: 我有以下foreach声明:

foreach (var articleId in cleanArticlesIds)
{
    var countArt = context.TrackingInformations.Where(x => x.ArticleId == articleId).Count();
    articleDictionary.Add(articleId, countArt);
}

Database looks like this 数据库看起来像这样

TrackingInformation(Id, ArticleId --some stuff
Article(Id, --some stuff

what I want to do is to get all the article ids count from TrackingInformations Table. 我想要做的是从TrackingInformations表中获取所有文章ID计数。 For example: 例如:

ArticleId:1 Count:1
ArticleId:2 Count:8
ArticleId:3 Count:5
ArticleId:4 Count:0

so I can have a dictionary<articleId, count> 所以我可以有一个dictionary<articleId, count>

Context is the Entity Framework DbContext. 上下文是实体框架DbContext。 The problem is that this solution works very slow (there are > 10k articles in db and they should rapidly grow) 问题在于此解决方案的运行速度非常慢(db中有> 10k的文章,并且它们应该迅速增长)

Try next query to gather grouped data and them add missing information. 尝试下一个查询以收集分组的数据,它们会添加缺少的信息。 You can try to skip Select clause, I don't know if EF can handle ToDictionary in good manner. 您可以尝试跳过Select子句,我不知道EF是否可以很好地处理ToDictionary

If you encounter Select n + 1 problem (huge amount of database requests), you can add ToList() step between Select and ToDictionary , so that all required information will be brought into memory. 如果遇到Select n + 1问题(大量数据库请求),则可以在SelectToDictionary之间添加ToList()步骤,以便将所有必需的信息带入内存。

This depends all your mapping configuration, environment, so in order to get good performance, you need to play a little bit with different queries. 这取决于您所有的映射配置和环境,因此为了获得良好的性能,您需要对不同的查询进行一些操作。 Main approach is to aggregate as much data as possible at database level with few queries. 主要方法是在很少查询的情况下在数据库级别聚合尽可能多的数据。

var articleDictionary = 
    context.TrackingInformations.Where(trackInfo => cleanArticlesIds.Contains(trackInfo.ArticleId))
                                .GroupBy(trackInfo => trackInfo.ArticleId)
                                .Select(grp => new{grp.Key, Count = grp.Count()})
                                .ToDictionary(info => "ArticleId:" + info.Key, 
                                              info => info.Count);

foreach (var missingArticleId in cleanArticlesIds)
{
    if(!articleDictionary.ContainsKey(missingArticleId))
        articleDictionary.add(missingArticleId, 0);
}

If TrackingInformation is a navigatable property of Article, then you can do this: 如果TrackingInformation是Article的可导航属性,则可以执行以下操作:

var result=context.Article.Select(a=>new {a.id,Count=a.TrackingInformation.Count()});

Putting it into a dictionary is simple as well: 将其放入字典也很简单:

var result=context.Article
  .Select(a=>new {a.id,Count=a.TrackingInformation.Count()})
  .ToDictionary(a=>a.id,a=>a.Count);

If TrackingInforation isn't a navigatable property, then you can do: 如果TrackingInforation不是可导航的属性,则可以执行以下操作:

var result=context.Article.GroupJoin(
          context.TrackingInformation, 
          foo => foo.id,
          bar => bar.id,
          (x,y) => new { id = x.id, Count = y.Count() })
       .ToDictionary(a=>a.id,a=>a.Count);

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

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