EF Core:Include预加载与直接上下文关联查询的性能对比及方案选择咨询
EF Core两种查询写法的性能对比与最优选择
首先先呼应官方提示的核心点:在单个查询中预加载集合导航属性确实可能引发性能问题,主要原因是会产生笛卡尔积,导致数据库返回大量重复的主实体数据,增加传输和客户端处理的开销。下面我们分别分析两种写法的特点:
写法一:使用Include+投影
var task = await context.Tasks .Include(x => x.TaskDependencies) .Select(x => new TaskBaseModel { Id = x.Id, Name = x.Name, Description = x.Description, TaskDependencies= x.TaskDependencies.ToArray() }) .SingleOrDefaultAsync(x => x.Id == _id);
工作原理与性能表现
- EF Core会生成单个JOIN查询,将
Tasks表和TaskDependencies表关联起来,返回的结果是笛卡尔积形式:比如一个Task有10个依赖,就会返回10条包含相同Task信息、不同依赖信息的记录。 - 之后EF Core会在客户端将这些重复的Task数据合并,把依赖项分组到对应的Task对象中。
- 优势:仅发起1次数据库请求,减少了网络往返次数,在依赖项数量极少时,性能表现尚可。
- 劣势:当依赖项数量较多时,会产生大量重复的Task字段数据,增加数据库传输的带宽消耗,同时客户端需要额外的内存和CPU来处理分组逻辑,整体开销会显著上升。
写法二:使用关联子查询
var task = await context.Tasks .Select(x => new TaskBaseModel { Id = x.Id, Name = x.Name, Description = x.Description, TaskDependencies= context.TaskDependencies .Where(y => y.TaskId == x.Id).ToArray() }) .SingleOrDefaultAsync(x => x.Id == _id);
工作原理与性能表现
- 这种写法会生成2次独立的数据库请求:第一次查询目标Task的基础信息,第二次根据TaskId查询对应的所有TaskDependencies。
- 优势:不会产生笛卡尔积,返回的数据都是必要的,没有重复的Task字段,数据库传输的数据量更小,客户端也无需处理分组逻辑,在依赖项较多时性能更优。
- 劣势:多了一次网络往返,但因为是查询单个Task(
SingleOrDefault),所以仅增加1次请求,对整体性能影响不大;但如果是批量查询多个Task时,这种写法容易引发N+1查询问题(每个Task都发起一次依赖查询),需要特别注意。
官方推荐的最优方案:拆分查询(Split Query)
针对集合导航属性预加载的性能问题,EF Core官方推荐使用拆分查询,也就是在Include后添加.AsSplitQuery(),它能自动将关联查询拆分为多个独立的查询,既避免笛卡尔积,又保持代码的简洁性:
var task = await context.Tasks .Include(x => x.TaskDependencies) .AsSplitQuery() .Select(x => new TaskBaseModel { Id = x.Id, Name = x.Name, Description = x.Description, TaskDependencies= x.TaskDependencies.ToArray() }) .SingleOrDefaultAsync(x => x.Id == _id);
为什么推荐拆分查询?
- 它会自动生成2次查询(和写法二类似):一次查Task,一次查对应的TaskDependencies,避免了笛卡尔积的开销。
- 代码写法更符合EF Core的惯用模式,通过
Include明确表达导航属性的关联关系,可读性和可维护性比写法二更优。 - 针对批量查询场景,拆分查询会生成2次批量查询(一次查所有Task,一次查所有对应的依赖),不会出现N+1问题,性能远优于写法二。
技术建议总结
- 如果是查询单个Task:拆分查询和写法二性能差异不大,但拆分查询代码更简洁,优先选择。
- 如果是批量查询多个Task:绝对避免写法二(容易N+1),优先使用拆分查询。
- 尽量避免写法一的单查询预加载集合导航属性,尤其是当集合元素数量较多时,笛卡尔积的开销会成为性能瓶颈。
- 可以开启EF Core的SQL日志,查看每种写法生成的SQL语句,直观理解查询的执行逻辑,帮助你做出更合适的选择。
内容的提问来源于stack exchange,提问作者MarchalPT
相关产品推荐
相关产品推荐

