【发布时间】:2016-12-07 15:00:42
【问题描述】:
我需要使用 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条记录执行时间(毫秒):
|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条记录执行时间(毫秒):
|1st Execution: 1286
|2nd Execution: 79
|3rd Execution: 67
为什么会有这样的差异(平均慢 2 倍)?如何提高查询性能?
更新:根据@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条记录执行时间(毫秒):
|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条记录执行时间(毫秒):
|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条记录执行时间(毫秒):
|1st Execution: 1427
|2nd Execution: 80
|3rd Execution: 76
【问题讨论】:
-
您在投影中包含一个带有连接的子查询,它自然会变慢
-
您没有在 Member.MemberWorkEntity 和 WorkEntity 之间直接导航? (你能添加一个吗?),你应该避免在选择中运行那个连接查询,因为它会为每个选定的项目循环运行。
-
@Tuco 自然会变慢,我的问题是我可以对查询进行哪些更改以使其更快。
-
我会问和@AndreiFilimon 一样的问题
-
子查询是主要的性能消耗。尝试重构您的查询以使用应该在 SQL 服务器(您是否使用 SQL 服务)端生成交叉应用的 GroupJoin,这会更快。另外,你在数据库上有所有正确的索引吗?
标签: c# sql-server linq entity-framework-6