如何使用20+包括改进EF查询性能()

时间:2013-06-07 05:23:02

标签: entity-framework linq-to-entities

我有一个Activity模型,可以从7种不同类型的模型中提取模型。这些模型也有它们的关系,活动源需要能够显示我想要的信息。这意味着我在查询中大约有20个包含。我只是这样做了8个月左右,我读过有关编译查询,存储过程以及所有这些内容可能会让我失望的内容。我还读到我可以将我的代码第一个模型更改为virtual,以便它可以进行延迟加载,但是我担心如果我有大量用户,所有这些数据库调用都会终止我的网站

首先是模型

public class Activity
{
    public int ActivityID { get; set; }
    public int ActivityTypeID { get; set; }
    public int ContributorID { get; set; }
    public int UserID { get; set; }
    public int? ProjectID { get; set; }
    public int? ProjectDocID { get; set; }
    public int? CommentID { get; set; }
    public int? BookID { get; set; }
    public int? BookReviewID { get; set; }
    public DateTime DateCreated { get; set; }
    public Comment Comment { get; set; }
    public ProjectDoc ProjectDoc { get; set; }
    public Project Project { get; set; }
    public Book Book { get; set; }
    public BookReview BookReview { get; set; }
    public ActivityType ActivityType { get; set; }
    [ForeignKey("ContributorID")]
    public User Contributor { get; set; }
    [ForeignKey("UserID")]
    public User User { get; set; }
    public ICollection<ActivityLike> ActivityLike { get; set; }
    public ICollection<ActivityComment> ActivityComment { get; set; }
}

现在查询

 var activity = db.Activities
                .Include(i => i.Contributor.BookStatus)
                .Include(i => i.ActivityType)
                .Include(i => i.ActivityLike.Select(y => y.User))
                .Include(i => i.ActivityComment.Select(y => y.User))
                .Include(i => i.Project.ProjectFollower)
                .Include(i => i.Project.View)
                .Include(i => i.Project.ProjectType)
                .Include(i => i.Project.User)
                .Include(i => i.Project.ProjectTag.Select(v => v.Tag))
                .Include(i => i.Project.ProjectCategory.Select(v => v.Category))
                .Include(i => i.Project.ProjectCharacteristic.Select(v => v.Characteristic))
                .Include(i => i.Project.ProjectDoc.Select(v => v.ProjectDocVote))
                .Include(i => i.Project.ProjectDoc.Select(v => v.User))
                .Include(i => i.Comment.User)
                .Include(i => i.Book.Author)
                .Include(i => i.Book.BookReview.Select(v => v.User))
                .Include(i => i.Book.BookReview.Select(v => v.BookReviewVote))
                .Include(i => i.Book.BookCharacteristic.Select(v => v.Characteristic))
                .Include(i => i.Contributor.Followers)
                .Where(u =>
                    u.Contributor.Followers.FirstOrDefault(x => x.FollowerID == WebSecurity.CurrentUserId) != null
                )
                .OrderByDescending(d => d.DateCreated)
                .Skip(offset)
                .Take(results)
                .ToList();

这就像6600行SQL(或其他任何东西)。

第一次运行需要10-16秒。因为我使用Skip()并使用jquery进行无限滚动,所以每次单个ajax调用首次需要10-12秒。因此,如果我每次获得10个结果并且有100个结果那么超过100秒的等待时间,这是非常糟糕的。现在,下次用户在短时间内访问该页面时,速度非常快。

那么我应该如何改进这个查询,你能否提供具体的方法并解释解决方案,因为我很难理解编译的查询,什么不能。我能够做到这一点的唯一原因是因为EF让它变得简单......这显然有成本。

请原谅并滥用行话。

3 个答案:

答案 0 :(得分:0)

我的建议:

  1. 确保正确调整数据库索引。无论您如何生成查询SQL,没有正确索引的连接都可能会导致性能下降。如果您使用的是SQL Server,那么使用Database Engine Tuning Advisor很容易。对于初学者来说,一般规则是应该对外键列进行索引。
  2. 考虑在普通的旧SQL中编写此关键路径查询。你已经在很短的时间内完成了实体框架上的一些技巧,我确信可能有一种方法可以优化你已经完成的工作,但是确保加速这个up是绕过ORM层。

答案 1 :(得分:0)

我选择切换到延迟加载,这将加载时间减少了70%。我意识到这不是理想的,因为更多的数据库往返,但如果网站增长,那么我会担心它。不理想,但我最初更关注性能。总而言之,我做了以下

在导航属性中添加了virtual。 删除了超重量查询中的几乎所有包含

结果是2.5秒加载时间而不是15秒(基于浏览器时间轴而不是sql profiler)。

答案 2 :(得分:-1)

在我的项目中,我创建了使用EF的存储库,所以我写了如下

  public IQueryable<Company> Companies
    {
        get
        {
            return context.Companies.Include("BankAccounts").Include("CompanyContacts").Include("MyClients").Include("MyCompanies").Include("Address");
        }
    }

现在我可以在我的代码公司的每个地方打电话,但不包括。

CompanyRepository comrep = new CompanyRepository();
var companies = comrep.Companies(c=>c.FullName == "Made in Azerbaijan").SingleOrDefault();

我希望这会对你有所帮助