EF Core在内存中而不是在SQL中执行GroupBy操作所需的解决方法

时间:2017-07-19 08:03:37

标签: c# entity-framework-core

我正在使用Entity Framework Core 1.1.0(此时升级不是一个选项,因为在以后的版本中会发生重大变化)。我的查询格式如下:

var q = db.MyTable
            .GroupBy(t => new { t.Field1 })
            .Select(g => new
            {
                g.Key.Field1,
                MaxField2 = g.Max(x => x.Field2)
            })
            .ToList();

在测试代码中,这很有效,并返回预期的数据。但是当使用真实数据部署到真实环境时,它会超时。为什么?好吧,我在SQL服务器上放了一个嗅探器,这是实际的SQL:

SELECT [t].[Field1], [t].[Field2], [t].[Field3], [t].[Field4], [t].[Field5]
FROM [dbo].[MyTable] AS [t]
ORDER BY [t].[Field1]

喔。好吧,这可以解释它。 EF仅将查询编译到SQL .GroupBy(),从而尝试将表中的整个内容(此时写入大约1700万条记录)加载到内存中,并且其余的分组和排序应该在内存中完成。

有关如何重写此查询的任何建议,以便在SQL中完成繁重的工作吗?

3 个答案:

答案 0 :(得分:3)

EF Core 1.1.0不支持:https://github.com/aspnet/EntityFramework/issues/2341

  

LINQ的GroupBy()运算符有时可以转换为SQL的GROUP BY子句,特别是在投影中应用聚合函数时。

遗憾的是,即使在EF Core 2.0.0中也不会支持它。

答案 1 :(得分:3)

正如@xanatos指出的那样,EF Core 1.1.0(甚至不是2.0.0)都不支持。但是,有一种解决方法,使用文字SQL:

var q = db.MyTable
        .FromSql("select t.* from " +
                 "  (select distinct Field1 from MyTable) t0 " +
                 "cross apply " +
                 "  (select top 1 t.* from MyTable t " +
                 "  where t.Field1 = t0.Field1 " +
                 "  order by t.Field2 desc) t")                     
        .Select(t => new
        {
            t.Field1,
            MaxField2 = t.Field2
        })
        .ToList();

不是我希望的解决方案,但它有魅力。

答案 2 :(得分:2)

正如您在blog entry中看到的那样,{1}}将在2.1中得到支持,但尚未发布,但expected for Q1-Q2 2018 2017年第4季度