2017-05-06 156 views
0

我有大约1 500 000个实体的Mysql数据库。当我尝试使用EF核心1.1以下语句来执行和Mysql.Data.EntityFrameworkCore 7.0.7-M61大约需要40分钟完成:使用本地的mysql-CLI和下面的语句EF Core Mysql性能

var results = db.Posts 
    .Include(u => u.User) 
    .GroupBy(g => g.User) 
    .Select(g => new { Nick = g.Key.Name, Count = g.Count() }) 
    .OrderByDescending(e => e.Count) 
    .ToList(); 

。另一方面,需要大约16秒完成。

SELECT user.Name, count(*) c 
FROM post 
JOIN user ON post.UserId = user.Id 
GROUP BY user.Name 
ORDER BY c DESC 

我做错了什么,或者EF核心性能的MySql是如此可怕?

+0

是user.name索引? –

+0

我不这么认为 – Marduk

+0

尝试启用记录执行的实际sql查询。我怀疑实际运行的内容离你写的查询很远。 执行EF生成的每个查询并在mysql-cli中运行它们并计时。你会发现瓶颈 – ironstone13

回答

1

您的查询正在做不同的事情。在LINQ到实体查询的一些问题:

  1. 你叫Include(...)将急切地加载User为每个项目在db.Posts
  2. 您可以拨打Count()查看每组中的每条记录。这可以重写为每组记录一次记录。
  3. 最大的问题是您只使用User对象的Name属性。你可以选择这个字段并找到相同的结果。在EF中选择,分组和返回150万个字符串应该是一个快速操作。

原文:

var results = 
    db.Posts 
     .Include(u => u.User) 
     .GroupBy(g => g.User) 
     .Select(g => new { Nick = g.Key.Name, Count = g.Count() }) 
     .OrderByDescending(e => e.Count) 
     .ToList(); 

建议:

var results = 
    db.Posts 
     .Select(x => x.User.Name) 
     .GroupBy(x => x) 
     .Select(x => new { Name = x.Key, Count = x.Count() }) 
     .OrderByDescending(x => x.Count) 
     .ToList(); 

如果EF核心仍然对类型分组,它允许报表的限制,你可以在第一次调用后ToListSelect(...)声明。

+0

那么你的例子已经减少了查询时间到144秒,但也花了2GB的内存。尽管如此,这比mysql-cli更糟糕。无论如何,这是一些进展。 – Marduk

+1

我每天都在使用EF,而且我很少运行查询,这些查询在原始SQL中的运行速度比EF中的速度快了几分之一秒(一旦完全指定和审查完毕)。如果您的项目团队允许,我建议您将EF Core交换为全EF,直到EF Core团队宣布它已准备好企业生产。缺乏数据库方面的分组(这个时候)让我们团队的项目锁定在EF 6中,尽管EF Core有着闪亮的吸引力。 –