实体框架6查询性能(M-M关系)

时间:2016-12-07 15:00:43

标签: c# sql-server linq entity-framework-6

我需要使用EF查询多个表中的多个列。当我在选择查询中不包含M-M关系时,一切顺利且性能良好。

使用M-M关系查询:

result = (from s in db.Member
                      .Include(i => i.Category)
                      .Include(i => i.MemberWorkEntity)
                      .Include(i => i.Status)
                      .Include(i => i.DiscountMethod)
                      .Where(i => i.C_deleted == null)
      select new MemberDTO
      {
          memberNumber = s.memberNumber,
          name = s.name,
          status = s.Status.name,
          email = s.email,
          phone = s.phone,
          mobile = s.mobile,
          fax = s.fax,
          workEntity = (from e in db.WorkEntity.Where(i => i.workEntityLevelID == 2)
                        join sc in s.MemberWorkEntity on e.workEntityID equals sc.workEntityID
                        select e.name).FirstOrDefault(),
          category = s.Category.name,
          discountMethod = s.DiscountMethod.name,
          delegate = s.delegate ? "Yes" : "No",
          leader = s.leader ? "Yes" : "No"

      }).AsNoTracking().ToList<MemberDTO>();

30000记录执行时间(ms):

|1st Execution: 1376
|2nd Execution: 160
|3rd Execution: 145

没有M-M关系的查询:

result = (from s in db.Member
                      .Include(i => i.Category)
                      .Include(i => i.MemberWorkEntity)
                      .Include(i => i.Status)
                      .Include(i => i.DiscountMethod)
                      .Where(i => i.C_deleted == null)
      select new MemberDTO
      {
          memberNumber = s.memberNumber,
          name = s.name,
          status = s.Status.name,
          email = s.email,
          phone = s.phone,
          mobile = s.mobile,
          fax = s.fax,
          //removed M-M Relationship Query
          category = s.Category.name,
          discountMethod = s.DiscountMethod.name,
          delegate = s.delegate ? "Yes" : "No",
          leader = s.leader ? "Yes" : "No"

      }).AsNoTracking().ToList<MemberDTO>();

30000记录执行时间(ms):

|1st Execution: 1286
|2nd Execution: 79
|3rd Execution: 67

为什么会有这样的差异(平均慢2倍)?如何提高查询性能?

更新:会员与WorkEntity之间的关系 M-M Relationship

更新:根据@ AndreFilimon的建议更新了我的查询:

IEnumerable<WorkEntity> workEntities = db.WorkEntity.AsNoTracking().Where(i => i.workEntityLevelID == 2);

result = (from s in db.Member
                      .Include(i => i.Category)                          
                      .Include(i => i.Status)
                      .Include(i => i.DiscountMethod)
                      .Where(i => i.C_deleted == null)
      select new MemberDTO
      {
          memberNumber = s.memberNumber,
          name = s.name,
          status = s.Status.name,
          email = s.email,
          phone = s.phone,
          mobile = s.mobile,
          fax = s.fax,
          workEntity = (from e in workEntities
                        join sc in s.MemberWorkEntity on e.workEntityID equals sc.workEntityID
                        select e.name).FirstOrDefault(),
          category = s.Category.name,
          discountMethod = s.DiscountMethod.name,
          delegate = s.delegate ? "Yes" : "No",
          leader = s.leader ? "Yes" : "No"

      }).AsNoTracking().ToList<MemberDTO>();

30000记录执行时间(ms):

|1st Execution: 1364
|2nd Execution: 122
|3rd Execution: 120

更新:在@agfc建议的基础上为我的会员表添加了一个简单的索引:

IEnumerable<WorkEntity> workEntities = db.WorkEntity.AsNoTracking().Where(i => i.workEntityLevelID == 2);

result = (from s in db.Member
                      .Include(i => i.Category)                          
                      .Include(i => i.Status)
                      .Include(i => i.DiscountMethod)
                      .Where(i => i.C_deleted == null)
      select new MemberDTO
      {
          memberNumber = s.memberNumber,
          name = s.name,
          status = s.Status.name,
          email = s.email,
          phone = s.phone,
          mobile = s.mobile,
          fax = s.fax,
          workEntity = (from e in workEntities
                        join sc in s.MemberWorkEntity on e.workEntityID equals sc.workEntityID
                        select e.name).FirstOrDefault(),
          category = s.Category.name,
          discountMethod = s.DiscountMethod.name,
          delegate = s.delegate ? "Yes" : "No",
          leader = s.leader ? "Yes" : "No"

      }).AsNoTracking().ToList<MemberDTO>();

30000记录执行时间(ms):

|1st Execution: 1544
|2nd Execution: 109
|3rd Execution: 105

更新:根据@ Klinger的回答更改了查询:

result = db.MemberWorkEntity.Where(mw => mw.WorkEntity.workEntityLevelID == 2 && mw.Member.C_deleted == null)
        .Select(s => new MemberDTO 
        {
            memberNumber = mw.Member.memberNumber,
            name = mw.Member.name,
            status = mw.Member.Status.name,
            email = mw.Member.email,
            phone = mw.Member.phone,
            mobile = mw.Member.mobile,
            fax = mw.Member.fax,
            workEntity = mw.WorkEntity.name,
            category = mw.Member.Category.name,
            discountMethod = mw.Member.DiscountMethod.name,
            @delegate = mw.Member.@delegate ? "Yes" : "No",
            leader = mw.Member.leader ? "Yes" : "No"
        }).ToList();

30000记录执行时间(ms):

|1st Execution: 1427
|2nd Execution: 80
|3rd Execution: 76

2 个答案:

答案 0 :(得分:1)

如果不查看实体的确切形状,请执行以下操作:

result = db.MemberWorkEntity.Where(mw => mw.WorkEntity.workEntityLevelID == 2 && mw.Member.C_deleted == null)
        .Select(s => new MemberDTO 
{
  memberNumber = mw.Member.memberNumber,
  name = mw.Member.name,
  status = mw.Member.Status.name,
  email = mw.Member.email,
  phone = mw.Member.phone,
  mobile = mw.Member.mobile,
  fax = mw.Member.fax,
  workEntity = mw.WorkEntity.name,
  category = mw.Member.Category.name,
  discountMethod = mw.Member.DiscountMethod.name,
  @delegate = mw.Member.@delegate ? "Yes" : "No",
  leader = mw.Member.leader ? "Yes" : "No"
}).ToList();

无需使用Include因为您投射到DTO而不是实体。 DTO将不具有您所包含实体的导航属性。 <{1}}用于在返回实体时进行预先加载。

答案 1 :(得分:0)

尝试在where子句之后移动包含,你也应该在这里获得一些整体性能: 同时将内部查询移出主查询以避免加入如下:

onClick