繁体   English   中英

LINQ不会使用EF Core在组上产生COUNT()查询

[英]LINQ does not produce COUNT() query on group using EF Core

我有一个ASP.NET Core应用程序,可通过EF Core在SQL Server 2012上运行。 我要实现的是计算不同群体的人数,例如

from b in this._context.Benchmark
group b by b.Device into g
select new {
    Device = g.Key,
    Count = g.Count()
}

问题是整个过程非常慢,其原因似乎是SQL语句未映射到GROUP BYCOUNT(*) ,但是根据调试器,应用程序请求所有内容并执行计数在CPU上。 我从调试器的事件窗口中获得的查询如下所示:

SELECT [b0].[ID], [b0].[CreateDate], [b0].[Creator], [b0].[Device], [b0].[Environment], [b0].[Machine], [b0].[Name], [b0].[Plugin], [b0].[RunDate]
FROM [Benchmark] AS [b0]
ORDER BY [b0].[Device]

我还可以看到,对于简单的COUNT() ,我用于调试的IIS Express的内存消耗是疯狂的,因此我倾向于认为这是实际的查询。

问题是:如何重新定义查询,使其实际上映射到COUNT()

编辑 :我已经尝试对“真实的” EF和ctx.Database.Log = Console.Write相同的查询,这会产生预期的COUNT()查询,这使我相信这是EF Core的问题。

请将EF Core升级到2.1.2版,现在支持。

LINQ表达式'GroupBy([x.Device],[x])'无法翻译,将在本地进行评估。

LINQ表达式'Count()'无法翻译,将在本地进行评估。

上面的日志来自我后来的测试结果,表明尚未支持GroupByCount()将完整的LINQ转换为SQL,然后直接在数据库中执行完整的SQL, 现在EF Core必须先获取所有数据,然后再获取GroupBy结果本地。 因此,如果您的数据量巨大,那么性能将非常糟糕。

您必须对一个简单的SQL进行硬编码才能直接在数据库中完成工作,然后性能将恢复正常。

我升级到EF Core 2.1.2,在MySQLMS SQL都尝试了以下代码:

var query = _context.Benchmark.GroupBy(x => x.Device, 
              (key, group) => new  //Result selector
              {
                  Device = key,
                  Count = group.Count()
              });
await query.ToListAsync();

结果选择器就在GroupBy内部,这将确保是否可以将其转换为正确的SQL,不幸的是,事实并非如此。

这是另一个棘手的问题,请避免使用Count

var query = _context.Benchmark.GroupBy(x => x.Device, 
              (key, group) => new  //Result selector
              {
                  Device = key,
                  Count = group.Select(g => g.Id)//Avoid to use Count
              });
await query.ToListAsync();

C#代码通过此工具生成以下日志:

2018-08-24T14:27:26.6737424-04:00 Information 10403 Microsoft.EntityFrameworkCore.Infrastructure
Entity Framework Core 2.1.2-rtm-30932 initialized 'ApplicationDbContext' using provider 'Pomelo.EntityFrameworkCore.MySql' with options: None
2018-08-24T14:27:31.4270317-04:00 Debug 10101 Microsoft.EntityFrameworkCore.Query
Compiling query model: 
'from IGrouping<Device, Benchmark> <generated>_0 in 
    (from Benchmark x in DbSet<Benchmark>
    select [x]).GroupBy([x].Device, [x])
select new <>f__AnonymousType3<Device, int>(
    [<generated>_0].Key, 

        (from Benchmark <generated>_1 in [<generated>_0]
        select [<generated>_1]).Count()
)'
2018-08-24T14:27:31.4319437-04:00 Debug 10104 Microsoft.EntityFrameworkCore.Query
Optimized query model: 
'from IGrouping<Device, Benchmark> <generated>_0 in 
    (from Benchmark x in DbSet<Benchmark>
    join Device x.Device in DbSet<Device>
    on Property([x], "DeviceId") equals Property([x.Device], "Id")
    select [x]).GroupBy([x.Device], [x])
select new <>f__AnonymousType3<Device, int>(
    [<generated>_0].Key, 

        (from Benchmark <generated>_1 in [<generated>_0]
        select [<generated>_1]).Count()
)'

这是核心LOGS,它表明还不支持GROUPBY

 2018-08-24T14:27:31.4431635-04:00 Warning 20500 Microsoft.EntityFrameworkCore.Query The LINQ expression 'GroupBy([x.Device], [x])' could not be translated and will be evaluated locally. 2018-08-24T14:27:31.4476637-04:00 Warning 20500 Microsoft.EntityFrameworkCore.Query The LINQ expression 'Count()' could not be translated and will be evaluated locally. 2018-08-24T14:27:31.4511652-04:00 Warning 20500 Microsoft.EntityFrameworkCore.Query The LINQ expression 'Count()' could not be translated and will be evaluated locally. 

以下是休息日志:

2018-08-24T14:27:31.4608060-04:00 Debug 10107 Microsoft.EntityFrameworkCore.Query
(QueryContext queryContext) => IAsyncEnumerable<<>f__AnonymousType3<Device, int>> _InterceptExceptions(
    source: IAsyncEnumerable<<>f__AnonymousType3<Device, int>> _SelectAsync(
        source: IAsyncEnumerable<IGrouping<Device, ValueBuffer>> _GroupBy(
            source: IAsyncEnumerable<TransparentIdentifier<ValueBuffer, Device>> _ShapedQuery(
                queryContext: queryContext, 
                shaperCommandContext: SelectExpression: 
                    SELECT `x.Device`.`Id`, `x.Device`.`Description`, `x.Device`.`IP`, `x.Device`.`Name`, `x.Device`.`Port`
                    FROM `Benchmark` AS `x`
                    INNER JOIN `Device` AS `x.Device` ON `x`.`DeviceId` = `x.Device`.`Id`
                    ORDER BY `x.Device`.`Id`, 
                shaper: TypedCompositeShaper<ValueBufferShaper, ValueBuffer, BufferedOffsetEntityShaper<Device>, Device, TransparentIdentifier<ValueBuffer, Device>>), 
            keySelector: (TransparentIdentifier<ValueBuffer, Device> t0) => t0.Inner, 
            elementSelector: (TransparentIdentifier<ValueBuffer, Device> t0) => t0.Outer), 
        selector: (IGrouping<Device, ValueBuffer> <generated>_0 | CancellationToken ct) => Task<<>f__AnonymousType3<Device, int>> _ExecuteAsync(
            taskFactories: new Func<Task<object>>[]{ () => Task<object> _ToObjectTask(Task<int> Count(
                        source: IAsyncEnumerable<ValueBuffer> _ToAsyncEnumerable(<generated>_0), 
                        cancellationToken: queryContext.CancellationToken)) }, 
            selector: (object[] results) => new <>f__AnonymousType3<Device, int>(
                <generated>_0.Key, 
                (int)results[0]
            ))), 
    contextType: Sequencer.Updater.Data.ApplicationDbContext, 
    logger: DiagnosticsLogger<Query>, 
    queryContext: queryContext)
2018-08-24T14:27:31.4825759-04:00 Debug 20000 Microsoft.EntityFrameworkCore.Database.Connection
Opening connection to database 'TestDB' on server 'localhost,3306'.
2018-08-24T14:27:31.4877302-04:00 Debug 20001 Microsoft.EntityFrameworkCore.Database.Connection
Opened connection to database 'TestDB' on server 'localhost,3306'.
2018-08-24T14:27:31.4901269-04:00 Debug 20100 Microsoft.EntityFrameworkCore.Database.Command
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT `x.Device`.`Id`, `x.Device`.`Description`, `x.Device`.`IP`, `x.Device`.`Name`, `x.Device`.`Port`
FROM `Benchmark` AS `x`
INNER JOIN `Device` AS `x.Device` ON `x`.`DeviceId` = `x.Device`.`Id`
ORDER BY `x.Device`.`Id`
2018-08-24T14:27:31.4929857-04:00 Information 20101 Microsoft.EntityFrameworkCore.Database.Command
Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT `x.Device`.`Id`, `x.Device`.`Description`, `x.Device`.`IP`, `x.Device`.`Name`, `x.Device`.`Port`
FROM `Benchmark` AS `x`
INNER JOIN `Device` AS `x.Device` ON `x`.`DeviceId` = `x.Device`.`Id`
ORDER BY `x.Device`.`Id`
2018-08-24T14:27:31.5231128-04:00 Debug 20300 Microsoft.EntityFrameworkCore.Database.Command
A data reader was disposed.
2018-08-24T14:27:31.5270399-04:00 Debug 20002 Microsoft.EntityFrameworkCore.Database.Connection
Closing connection to database 'TestDB' on server 'localhost,3306'.
2018-08-24T14:27:31.5303748-04:00 Debug 20003 Microsoft.EntityFrameworkCore.Database.Connection
Closed connection to database 'TestDB' on server 'localhost,3306'.

这是我的环境:

PM> dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   2.1.401
 Commit:    91b1c13032

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.16299
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.1.401\

Host (useful for support):
  Version: 2.1.3
  Commit:  124038c13e

.NET Core SDKs installed:
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.302 [C:\Program Files\dotnet\sdk]
  2.1.400 [C:\Program Files\dotnet\sdk]
  2.1.401 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

暂无
暂无

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

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