c# - EF Core 3.1 查询优化
问题描述
我不时听到,EF Core 3.1 现在能够优化分组和几个聚合函数,如 sum 以在数据库上执行。为什么我的 C# 代码会将此严重未优化的 SQL 代码发送到数据库服务器?
using var dbContext = new DatabaseContext();
var someTableData = await dbContext.SomeTable
.GroupBy(x => x.Foobar)
.Select(x => new { Foobar = x.Key, Quantity = x.Sum(y => y.Quantity) })
.OrderByDescending(x => x.Quantity)
.Take(10)
.ToListAsync();
SQL(从实体框架日志复制):
SELECT [...] FROM public."SomeTable"
如您所见:查询不包含任何排序、分组、汇总...
我通过创建一个视图解决了我的问题,因为原始的 ef 核心查询将应用程序的 RAM 使用量增加了 2GB(在 2 秒内),因为有很多表条目。但我的问题仍然存在:我做错了什么?是因为我使用的是 PostgreSQL(Npgsql.EntityFrameworkCore.PostgreSQL v3.1.0)吗?
解决方案
我将您的查询弹出到一个快速测试工具中(请参阅下面所有 nuget 包版本的项目定义):
public class SomeTable
{
public int Id { get; set; }
public int Foobar { get; set; }
public int Quantity { get; set; }
}
class MyDbContext : DbContext
{
public DbSet<SomeTable> SomeTables { get; set; }
public static readonly LoggerFactory DbCommandConsoleLoggerFactory
= new LoggerFactory(new[] {
new ConsoleLoggerProvider ((category, level) =>
category == DbLoggerCategory.Database.Command.Name &&
level == LogLevel.Trace, true)
});
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("Server=...;Port=5432;Database=test;User Id=...;Password=...;")
//optionsBuilder.UseSqlServer("Server=.\\SQLEXPRESS;Database=test;Trusted_Connection=true")
.UseLoggerFactory(DbCommandConsoleLoggerFactory)
.EnableSensitiveDataLogging();
base.OnConfiguring(optionsBuilder);
}
}
class Program
{
static void Main(string[] args)
{
var context = new MyDbContext();
var someTableData = context.SomeTables
.GroupBy(x => x.Foobar)
.Select(x => new { Foobar = x.Key, Quantity = x.Sum(y => y.Quantity) })
.OrderByDescending(x => x.Quantity)
.Take(10);
Console.Write(someTableData);
Console.ReadKey();
}
}
/*csproj file contents below:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>ef_core3_playground</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.1" />
</ItemGroup>
</Project>
*/
我最终为各自的提供者获得了以下 SQL:
--MS SQL
SELECT TOP(@__p_0) [s].[Foobar], SUM([s].[Quantity]) AS [Quantity]
FROM [SomeTables] AS [s]
GROUP BY [s].[Foobar]
ORDER BY SUM([s].[Quantity]) DESC
-- PG SQL
SELECT s."Foobar", SUM(s."Quantity")::INT AS "Quantity"
FROM "SomeTables" AS s
GROUP BY s."Foobar"
ORDER BY SUM(s."Quantity")::INT DESC
LIMIT @__p_0
这让我想知道是否可能是您的提供程序/EF 特定版本给您带来了这种结果?虽然查看两个 npgsql 版本之间的差异,但我看不到与该问题相关的任何内容,但我建议您尝试将所有与 EF 相关的软件包升级到3.1.1
并重复您的测试。
推荐阅读
- java - Sublime text 问题(javac: invalid flag:)
- terraform - terraform 模块如何根据调用者传递的参数(变量)返回不同的值
- html5-video -
- android - 当应用程序被杀死时,FCM 不工作
- xaml - 有没有办法动态获取 ListView 项的 RowHeight 以用于设置 Grid 列的宽度?
- azure - Azure 服务总线主题、订阅规则已删除
- javascript - 如何在 Angular 中动态生成不同的变量?
- javascript - 正则表达式从html中提取属性作为文本
- image - Flutter 应用中的 webP 动画图像会在 iOS 上显示吗?
- python - 散景工具提示获得 Y 值顶部