🚀 只读查询的“零分配”之路:EF Core + Dapper + MemoryPack 的组合优化
目标:在只读接口的热路径上,把关键路径上的临时对象与复制降至最低,降低 GC 压力与 p95/p99 尾延迟,提升吞吐。
主线(“三轨并行”)
- EF Core:编译查询 +
AsNoTracking()+ 显式投影(中低 QPS 的默认路径); - Dapper:手写 SQL + 非缓冲流式(
buffered:false)+ 扁平 DTO(热点/大结果集); - 序列化:MemoryPack +
HttpResponse.BodyWriter(IBufferWriter<byte>)直写;浏览器/通用生态 → 回退 System.Text.Json(配 Source Generator)。
ℹ️ 术语澄清:“零分配”是工程目标,即尽量将关键路径上的中间对象/复制去除或显著降低;受字符串、网络缓冲、运行库内部对象等影响,端到端“绝对零分配”不可达。
📚 目录
- 🚀 只读查询的“零分配”之路:EF Core + Dapper + MemoryPack 的组合优化
🏗️ 架构鸟瞰(三轨并行总览)
1) 🧭 适用与边界
- 适用:只读 API、列表页、导出、报表快照;一致性级别以“读已提交/快照读”为主。
- 暂不讨论:复杂对象图(建议显式投影 DTO,避免
Include拉整图)、强事务读写混合。
2) ⚙️ 三轨并行:总体设计
-
EF Core 轨(可维护):
AsNoTracking()+ 投影 DTO + 编译查询;用TagWith("hotpath:...")标注,便于日志/执行计划定位。编译查询把 LINQ 预编译为委托,适合高重复度查询(是否采用以基准评估为准)。 -
Dapper 轨(性能优先):
稳定 SQL + 扁平 DTO,必要时buffered:false非缓冲流式,明显降低大结果集峰值内存(连接在枚举全过程必须保持打开)。 -
序列化/输出轨:
MemoryPack 以IBufferWriter<byte>/PipeWriter直写;Accept不支持时回退 System.Text.Json(建议启用 Source Generation 以减少反射、兼容 AOT/Trim)。对BodyWriter,调用FlushAsync才会把缓冲推入响应体。
3) 🧩 EF Core:编译查询 + 禁跟踪 + 显式投影
准则
- 编译查询:
EF.CompileQuery/CompileAsyncQuery将 LINQ 表达式编译为委托,绕过查询缓存查找,在高重复度场景更优(先做基准)。 - 只读禁跟踪:
AsNoTracking()是只读查询的常规选择;AsNoTrackingWithIdentityResolution会在无跟踪下做身份解析(去重相同主键实例),仅在确需语义时使用。 - 查询标签:
TagWith("hotpath:xxx")写入 SQL 注释,帮助把 LINQ 与生成 SQL/日志对应。
示例
// EF Core 8/9
using Microsoft.EntityFrameworkCore;
public sealed record OrderDto(int Id, string No, decimal Amount, DateTime CreatedAt);
public static class Queries
{
// 编译查询:只读 + 投影 + 限制条数
public static readonly Func<AppDbContext, int, IAsyncEnumerable<OrderDto>>
GetRecentOrders = EF.CompileAsyncQuery((AppDbContext db, int take) =>
db.Orders
.TagWith("hotpath:list-orders") // 起始处标注,便于日志/执行计划定位
.AsNoTracking()
.OrderByDescending(x => x.CreatedAt)
.Select(x => new OrderDto(x.Id, x.No, x.Amount, x.CreatedAt))
.Take(take));
}
4) 🧵 Dapper:扁平 DTO + 非缓冲流式(热点/大结果集)
- 列顺序与 DTO 对齐,降低映射开销;
- 非缓冲:
buffered:false使结果延迟枚举,结合“边读边写”显著降低峰值内存;务必保证连接在枚举全过程保持打开; - AOT/裁剪友好:可评估 Dapper.AOT(构建期生成/拦截器),减少运行时反射/发射。
示例(流式 JSON:取消令牌 + 分段 Flush + STJ SourceGen + 统一限量 + 无 RegisterForDispose)
using System.Data;
using System.Text.Json

最低0.47元/天 解锁文章
1322

被折叠的 条评论
为什么被折叠?



