EF Core 慢下来的三种方式,我们全踩过了
用 EF Core 三年,性能问题来来回回就这三类。写下来当检查清单,每次接口超时先对着过一遍。
一,N+1 查询。延迟加载开着,循环里访问导航属性,每个元素都单独发一条 SQL。列表页查 100 条博客再显示每篇的作者,就是 1 + 100 条查询。修法是预加载:
var blogs = await db.Blogs
.Include(b => b.Author)
.AsNoTracking()
.ToListAsync();
二,无谓的跟踪。EF 默认给查回来的每个实体做变更跟踪快照,列表页根本不更新数据,这些快照全是白算的。只读场景加 AsNoTracking(),聚合场景更进一步用 Select 投影,直接让数据库算平均值,只传结果不传实体。
三,客户端求值。Where 里写了个 C# 方法,EF 悄悄把它翻译成"全表拉回来在内存里过滤"——结果对,性能死。日志里看到 SQL 没有 WHERE 就该警觉。新版 EF 对这种写法会直接抛异常,把老项目的开关打开,很多隐患自己就冒出来了。

配套建议:开发环境把 EF 的命令日志打开,每条 SQL 看一眼。N+1 和客户端求值在日志里一目了然,比上线后翻性能报表早发现一整个量级。
这三条都治完,那个超时的报表接口从 4 秒降到了 200 毫秒。没有黑科技,全是基本功。