[英]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 BY
和COUNT(*)
,但是根据调试器,应用程序请求所有内容并执行计数在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()'无法翻译,将在本地进行评估。
上面的日志来自我后来的测试结果,表明尚未支持GroupBy
& Count()
将完整的LINQ转换为SQL,然后直接在数据库中执行完整的SQL, 现在EF Core必须先获取所有数据,然后再获取GroupBy
结果本地。 因此,如果您的数据量巨大,那么性能将非常糟糕。
您必须对一个简单的SQL进行硬编码才能直接在数据库中完成工作,然后性能将恢复正常。
我升级到EF Core 2.1.2,在MySQL
和MS 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.