我有一个将数据分组两次的查询:
var query = (from a in Context.SetA()
from b in Context.SetB().Where(x => x.aId == a.Id) // 1-to-many
from c in Context.SetC().Where(x => x.bId == b.Id) // 1-to-many
group new {...} by new {...} into g
select new
{
g.Key.X,
g.Key.Y,
g.Sum(x => x....), // etc, lots of Sums
});
from (q in query
group q by true
select new
{
g.Key.Z,
g.Sum(x => x.....), // etc, lots of Sums
});
这一切都运作良好,性能可以接受。现在,当我在两个分组中添加All(或Any,没有任何区别)
g.All(x => x.Flag)
性能急剧下降。它变得慢了10倍,从5s变为50s。数字不准确,只是为了得到这个想法。
我正在进行两次分组,因为我有三个级别的1对多关系,并且我在所有级别上做总结(父级的总和,子级的总和以及孙子的值的总和)。
我有什么想法可以提高绩效?
答案 0 :(得分:4)
问题是没有自然的SQL GROUP BY
聚合可以映射到应用于分组的All
/ Any
,因此EF SQL转换效率低下。
解决方案是使用它们的聚合等价物。
所以而不是
g.All(x => x.Flag)
你可以使用
g.Min(x => x.Flag ? 1 : 0) == 1
和
g.Any(x => x.Flag)
可以替换为
g.Max(x => x.Flag ? 1 : 0) == 1
更新:奇怪的是,EF为上述表达式生成了2 MIN
/ MAX
次调用。通过在末尾添加(== 1
之后)反直觉? true : false