Entity Framework Core 运行缓慢或盲目工程师
Source: Dev.to
Entity Framework Core 是 .NET 生态系统中最具生产力的工具之一。
它让团队能够快速前进、干净地建模领域,并迅速交付功能。你可以在不深入了解数据库内部工作细节的情况下编写代码,这既是优势也是劣势。
EF Core 在项目规模不大时表现很好——但项目一旦扩大,就会出现问题。
- 更多数据
- 更多关系
- 更多边缘情况
- 更多对性能敏感的路径
此时,问题开始显现,EF 常常被指责。工程师可能会添加额外的索引,但这只能暂时掩盖问题。
根本原因: 工程师根本不知道 EF 查询是如何转换成 SQL 的。
在许多成熟的代码库中,LINQ 查询的编写并未考虑它们如何翻译成 SQL。小规模时这往往不被注意:
- 记录少
- 并发低
- 延迟可接受
但随着数据增长,那些“无辜”的查询可能会变成:
- 意外的多表连接
- N+1 查询
- 全表扫描
- 过度的内存使用
- 未优化的执行计划
EF Core 并不隐藏 SQL——它会生成 SQL。如果你不理解生成的 SQL,就等于在盲目编码。
来自生产环境的真实案例
几年前,在调查生产系统的性能问题时,我发现了以下遗留代码:
- 将数百个实体加载到内存中
- 启用了更改跟踪
- 在循环中更新它们
- 调用了
SaveChangesAsync()
var cutoff = nowUtc.AddDays(-90);
var users = await db.Users
.Where(u =>
u.Status == UserStatus.Active &&
(u.LastLoginUtc == null || u.LastLoginUtc
u.Status == UserStatus.Active &&
(u.LastLoginUtc == null || u.LastLoginUtc setters
.SetProperty(u => u.Status, UserStatus.Archived)
.SetProperty(u => u.UpdatedAtUtc, nowUtc),
ct);
根本原因并不是“EF 运行慢”。而是使用了 ORM 抽象却没有理解其代价。
经验教训
- 了解 LINQ 是如何转换为 SQL 的。
- 知道何时需要更改跟踪——以及何时不需要。
- 识别查询何时应采用集合方式、编译方式或直接使用原始 SQL。
- 为任务选择合适的工具:有时 EF Core 是理想选择;而在其他情况下,存储过程、视图或原始查询可能更合适。
如果你不了解它的工作原理,就不要把问题归咎于工具本身。