EF Core单查询与拆分查询的选择及全局默认配置最佳实践
EF Core 单查询与拆分查询的最佳实践及常见问题解答
全局默认执行策略
EF Core 5及以上版本(包括你使用的EF Core 7)的默认执行模式为单查询(Single Query)。若要全局切换为拆分查询,可在DbContext配置中设置:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("YourConnectionString", options => options.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)); }
也可通过单查询上的AsSplitQuery()覆盖全局配置,或用AsSingleQuery()强制使用单查询模式。
单条记录查询场景是否始终适合拆分查询?
并非绝对,需结合数据规模判断:
- 适合拆分查询:当单条主记录关联的多个集合数据量较大时,单查询会产生笛卡尔积,导致数据冗余、内存占用过高,拆分查询通过多次单表查询获取数据,性能更优。比如你示例中用户关联的角色、角色声明数据较多时,拆分查询更合适。
- 不适合拆分查询:如果关联的集合数据量极小(比如每个用户仅1-2个角色,每个角色仅几个声明),单查询的笛卡尔积额外开销可忽略,一次查询即可获取所有数据,比多次数据库往返的拆分查询效率更高。
两种模式的最佳实践
单查询(Single Query)
- 适用场景:
- 查询主记录关联的集合数量少、数据量小的场景
- 需要保证查询原子性(如事务中执行,避免拆分查询期间数据被修改)
- 对数据库往返次数敏感的场景(如数据库延迟较高的环境,减少往返能提升性能)
- 注意:包含多个集合时会触发
MultipleCollectionIncludeWarning,若确认数据量小无性能问题,可通过配置抑制警告:
optionsBuilder.ConfigureWarnings(warnings => warnings.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.CoreEventId.MultipleCollectionIncludeWarning));
拆分查询(Split Query)
- 适用场景:
- 查询包含多个大集合的关联数据,避免笛卡尔积导致的性能问题
- 主记录数量少,但每个主记录关联的集合数据量较大的场景
- 注意事项:
- 拆分查询会发起多次数据库请求,可能受数据库并发修改影响(如第一次查询主记录后,关联集合数据被修改,导致数据不一致)
- 结合
Skip/Take分页时,必须保证排序条件唯一,否则多次查询可能返回不一致的分页结果。例如用主键+其他字段排序,避免相同排序值导致的记录顺序不确定:var users = await _userManager.Users .Include(x => x.UserRoles) .OrderBy(u => u.Id) // 主键唯一,保证排序稳定 .Skip(10) .Take(5) .AsSplitQuery() .ToListAsync();
针对你的示例代码的建议
你的查询是获取单条用户记录及其关联的角色、角色声明,可先评估关联数据规模:
- 若用户的角色和声明数据量不大,保留单查询即可,同时可抑制对应警告
- 若数据量较大,
AsSplitQuery()是更合适的选择,能避免笛卡尔积带来的性能损耗
内容的提问来源于stack exchange,提问作者curiousBoy
相关产品推荐
相关产品推荐

