【问题标题】:Slow EF query grouping data by Month/Year慢速EF查询按月/年分组数据
【发布时间】:2015-10-09 17:26:49
【问题描述】:

我有大约 100 万条记录的记录集。我正在尝试查询记录以报告月度数据。

以下 MySQL 查询在大约 0.3 秒内执行

SELECT SUM(total), MONTH(create_datetime), YEAR(create_datetime) 
FROM orders GROUP BY MONTH(create_datetime), YEAR(create_datetime)

但是我无法找出一个可以尽可能快地执行的实体框架 lambda 表达式

我想出的唯一有效的说法是

var monthlySales = db.Orders
                     .Select(c => new
                     {
                         Total = c.Total,
                         CreateDateTime = c.CreateDateTime
                     })
                     .GroupBy(c => new { c.CreateDateTime.Year, c.CreateDateTime.Month })
                     .Select(c => new
                     {
                         CreateDateTime = c.FirstOrDefault().CreateDateTime,
                         Total = c.Sum(d => d.Total)
                     })
                     .OrderBy(c => c.CreateDateTime)
                     .ToList();

但是速度太慢了。

如何让这个查询像直接在 MySQL 中一样快速执行

【问题讨论】:

  • 发送到服务器的实际 SQL 命令是什么?我们需要了解速度问题是服务器端还是客户端。

标签: c# mysql entity-framework ef-code-first


【解决方案1】:

当您在查询中间(在进行分组之前)执行“.ToList()”时,EF 将有效地从内存中的数据库中查询所有订单,然后在 C# 中进行分组。根据您表中的数据量,这可能需要一段时间,我认为这就是您的查询如此缓慢的原因。

尝试重写您的查询,只使用 1 个枚举结果的表达式(ToList、ToArray、AsEnumerable)

【讨论】:

  • 去掉初始的.ToList()后,查询速度似乎没有任何变化(大约1分钟)
  • 你现在检查过查询生成的SQL了吗? ((ObjectQuery)yorquery).ToTraceString() 目前我没有 Mysql 框来确定测试,但我认为如果你从 db.Orders.GroupBy() 开始然后从这个中选择它应该可以工作。
【解决方案2】:

试试这个:

var monthlySales = from c in db.Orders
                   group c by new { y = c.CreateDateTime.Year, m = c.CreateDateTime.Month } into g
                   select new {
                       Total = c.Sum(t => t.Total),
                       Year = g.Key.y,
                       Month = g.Key.m }).ToList();

【讨论】:

    【解决方案3】:

    我遇到了这个执行速度很快的设置

                var monthlySales = db.Orders
                     .GroupBy(c => new { Year = c.CreateDateTime.Year, Month = c.CreateDateTime.Month })
                     .Select(c => new
                     {
                         Month = c.Key.Month,
                         Year = c.Key.Year,
                         Total = c.Sum(d => d.Total)
                     })
                     .OrderByDescending(a => a.Year)
                     .ThenByDescending(a => a.Month)
                     .ToList();
    

    【讨论】:

    • 是的,你应该这样做。与我的回答类似,但我使用了我认为更具可读性和更短的 LINQ。
    • @RacilHilan 如果他移动了 2 行订购代码,代码长度几乎相同。使用查询或方法语法只是一种偏好。在许多情况下查询语法更短(但不是在这种情况下),但在许多情况下我们必须使用方法语法。对我来说,方法语法在 OOP 和流畅语法方面看起来更好,查询在类似 SQL 的语法方面看起来更好。
    • @KingKing 你所说的没有什么我不同意的:-)。我明确说过你应该这样做,但我只是想说明两个答案是相似的,所以OP和其他人可以选择他们喜欢的。其余的都是我自己的意见,所以我说我认为。我个人总是使用查询语法,除了两种情况:1)当我们必须时,就像你说的那样。 2)当我只需要一个或两个方法调用时,因为它比这种情况下的查询更短更清晰。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多