我需要帮助加速这个 EF LINQ 查询。

3
我正在使用EntityFramework 6,但遇到了一些严重的速度问题-- 这个查询要运行超过两秒钟。我花了一整天的时间使用LinqPad来加快查询速度,但我只能将其从4秒减少到2秒。我尝试了分组、连接等,但是生成的SQL对我来说看起来过于复杂。我猜想我可能只是在编写LINQ时采取了错误的方法。
以下是我的尝试:
1.查找所有Valid为null且AccountId不是当前用户的A对象。
2.确保B集合中不包含AccountId为当前用户的任何B对象。
3.按其集合中的B数量降序排序所得到的A对象。
4.任何没有B对象的A对象应该在返回结果的末尾。
我的模型如下:
public class A
{
    public int Id { get; set; }
    public bool? Valid { get; set; }
    public string AccountId { get; set; }
    public virtual ICollection<B> Collection { get; set; }
}

public class B
{
    public int Id { get; set; }
    public bool Valid { get; set; }
    public string AccountId { get; set; }
    public DateTime CreatedDate { get; set; }
    public virtual A Property { get; set; }
}
< p >表A有大约一百万行,而B最终将拥有约一千万行。目前B只有50000行。< /p> < p >以下是当前查询的样子。虽然它给出了预期的结果,但我必须多次运行orderby和其他不必要的步骤:< /p>
var filterA = this.context.A.Where(gt => gt.Valid == null && !gt.AccountId.Contains(account.Id));

var joinedQuery = from b in this.context.B.Where(gv => !gv.AccountId.Contains(account.Id))
                            join a in filterA on gv.A equals a
                            where !a.Collection.Any(v => v.AccountId.Contains(account.Id))
                            let count = gt.Collection.Count()
                            orderby count descending 
                            select new { A = gt, Count = count };

IQueryable<GifTag> output = joinedQuery
                .Where(t => t.A != null)
                .Select(t => t.A)
                .Distinct()
                .Take(20)
                .OrderBy(t => t.Collection.Count);

谢谢


在测量查询的执行时间时,是否包括 EF 的预热时间或者在测量之前运行了另一个查询?此外,这是您第一次运行特定的查询吗?我相信 EF 6 会自动构建编译查询,这将使每个查询的第一次执行需要更长的时间。 - Morten Christiansen
1
这些表中有多少行?您已经设置了一些索引吗?为什么AccountId是字符串类型的? - Marian Ban
表之间的关系是什么?它包含哪些列? - user1429080
@MortenChristiansen - 是的,我在LinqPad中运行了多次查询。第一次肯定会慢一些。 - John Kalberer
@MajoB - 依赖属性有索引。我还添加了一个到AccountId。它是一个字符串,因为这是EF Identity在AspNetUsers表中生成的方式。 - John Kalberer
@JohnKalberer 你需要执行 gt.AccountId.Contains(acocunt.Id) 而不是 gt.AccountId == account.Id 吗? - Marian Ban
1个回答

1

你可以尝试从joinQuery中删除这两行:

where !a.Collection.Any(v => v.AccountId.Contains(account.Id))

orderby count descending

第一行已经在第一个查询中被过滤了, 而排序,可以在最后一个查询中进行,所以没有必要做两次。


我刚试着删除了一个Contains,它确实加速了查询。我需要确保它实际上返回了正确的行。由于某种原因,我不得不多次使用orderby,否则在分组后进行其他查询时顺序会错乱。 - John Kalberer
我猜这个查询比我想象的简单得多。移动Any离开联接就可以了。 - John Kalberer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接