如何处理‘QuerySplittingBehavior’警告并优化EF查询?
优化EF查询活跃Subject数量的方案
你当前的写法存在两个问题:一是用Include筛选关联实体后计数,完全没必要,还触发了EF的拆分查询警告;二是这段代码实际统计的是符合StudentId条件的Domain实体数量,根本不是关联的活跃Subject数量——这大概率是逻辑错误。
最优方案:直接从Subject表统计
既然Domain和Subject是一对多关系,Subject肯定有对应Domain的外键(比如DomainId)。直接从Subject表入手统计,减少关联层级,性能最高:
await _context.Subjects .Where(s => s.Domain.StudentId == request.Id && s.Active == 0) .CountAsync();
如果Subject表直接存了StudentId(不用绕Domain关联),写法更简单:
await _context.Subjects .Where(s => s.StudentId == request.Id && s.Active == 0) .CountAsync();
必须从Domain出发的情况
如果业务逻辑要求从Domain实体关联查询,要避免警告同时正确统计,用SelectMany展开关联集合再计数就行:
await _context.Domain .Where(d => d.StudentId == request.Id) .SelectMany(d => d.Subjects.Where(s => s.Active == 0)) .CountAsync();
关于拆分查询警告的说明
这个警告是因为EF默认的SingleQuery模式加载关联数据时,可能生成笛卡尔积查询,导致数据冗余、性能下降。而上面的写法都不用Include——Include是用来把关联实体加载到内存的,你要的只是计数,根本不需要加载实体,直接让数据库完成统计就好,自然不会触发警告。
总结
- 优先直接查询Subject表,性能最优
- 别用
Include做统计,它的作用是加载实体到内存,不是筛选计数 - 从Domain出发统计的话,用
SelectMany展开集合再计数是正确方式
内容的提问来源于stack exchange,提问作者dave_bell
相关产品推荐
相关产品推荐

