我正在为一所抓住活跃学生的大学制作一个计划,然后为其他流程提供报告。
其中一项重要功能是查看学生是否已毕业。
当学生通过主要功能时,通过该过程大约需要5秒钟。我发现参与该过程的最多时间来自此函数中的IQueryable.First()
。
public static bool ContinuingEducation(string v)
{
var TERMSSTU = from t in _DB.TERMs
join stu in _DB.STUDENT_TERMS_VIEWs
on t.TERMS_ID equals stu.STTR_TERM
where v == stu.STTR_STUDENT
orderby t.TERM_START_DATE descending
select new { startdate = t.TERM_START_DATE };
var graduation = from a in _DB.ACAD_CREDENTIALs
where v == a.ACAD_PERSON_ID
orderby a.ACAD_COMMENCEMENT_DATE ascending
select a;
if (graduation.Count() > 0 && TERMSSTU.Count() > 0)
{
if (TERMSSTU.First().startdate > graduation.First().ACAD_COMMENCEMENT_DATE) // the problem is here
return true;
}
return false;
}
我不知道为什么这么久需要这么久。是否有更好的方法来写出这个函数,因为它更快?
答案 0 :(得分:4)
您对Count
的使用效率很低,因为您需要多次查询数据库(一次获取Count
,一次获取First
)。以下代码更改将无需获取Count
。
变化:
if (graduation.Count() > 0 && TERMSSTU.Count() > 0)
{
if (TERMSSTU.First().startdate > graduation.First().ACAD_COMMENCEMENT_DATE) // the problem is here
return true;
}
return false;
为:
var grad = graduation.FirstOrDefault();
var term = TERMSSTU.FirstOrDefault()
if (grad == null || term == null)
return false;
return term.startdate > grad.ACAD_COMMENCEMENT_DATE;
请注意,即使进行此更改,FirstOrDefault
仍然可能会很慢。要解决此问题,您应该运行SQL Trace
以查看正在生成的SQL。然后查看add indexes /优化查询。
答案 1 :(得分:2)
尝试代码
public static bool ContinuingEducation(string v)
{
var TERMSSTU = (from t in _DB.TERMs.AsQueryable()
join stu in _DB.STUDENT_TERMS_VIEWs.AsQueryable()
on t.TERMS_ID equals stu.STTR_TERM
where v == stu.STTR_STUDENT
orderby t.TERM_START_DATE descending
select new { startdate = t.TERM_START_DATE }).FirstOrDefault();
var graduation = (from a in _DB.ACAD_CREDENTIALs.AsQueryable()
where v == a.ACAD_PERSON_ID
orderby a.ACAD_COMMENCEMENT_DATE ascending
select a).FirstOrDefault();
if (graduation==null || TERMSSTU==null)
return false;
return TERMSSTU.startdate >graduation.ACAD_COMMENCEMENT_DATE;
}
答案 2 :(得分:0)
性能问题不在First
调用中,而在查询中。当您致电First
时会对其进行评估。
您应该重写代码以使用较少的查询:eq您可以在v
参数上加入两个查询,然后获取结果并检查它的日期。它将导致单个查询。
答案 3 :(得分:0)
我最好的办法是获得一些严肃的效率,就是在程序开始时查询这些记录,这样所有记录都在内存中,这使得程序的查询变得轻而易举。
我创建了一个捕获这两个查询的新类
公共类TERMSTU { 公共日期时间? startdate {get;组; } public String Id {get;组; } }
公共课毕业 { 公共日期时间? ACAD_COMMENCEMENT_DATE {get;组; } public String Id {get;组; } } 公共课报告 { 私人清单TERMSSTUS; 私人名单毕业; 公共报告(ColleagueDataContext _DB) { var TERMSSTU =来自_DB.TERMs中的t 在_DB.STUDENT_TERMS_VIEWs中加入stu 在t.TERMS_ID等于stu.STTR_TERM orderby t.TERM_START_DATE降序 选择新{startdate = t.TERM_START_DATE,id = stu.STTR_STUDENT}; TERMSSTUS =新名单(); foreach(TER IS中的var i) { TERMSSTUS.Add(new TERMSTU(){Id = i.id,startdate = i.startdate}); } var graduation = from a in _DB.ACAD_CREDENTIALs
where a.ACAD_COMMENCEMENT_DATE != null
where a.ACAD_COMMENCEMENT_DATE < DateTime.Today
orderby a.ACAD_COMMENCEMENT_DATE descending
select a;
GRADUATIONS = new List<Graduation>();
foreach (var i in graduation)
{
GRADUATIONS.Add(new Graduation() { Id = i.ACAD_PERSON_ID, ACAD_COMMENCEMENT_DATE = i.ACAD_COMMENCEMENT_DATE });
}
}
public List<TERMSTU> givestu()
{
return TERMSSTUS;
}
public List<Graduation> givegrad()
{
return GRADUATIONS;
}
}
我修改了该功能以进行两次查询
public static bool ContinuingEducation(string v, List<TERMSTU> t, List<Graduation> g)
{
var term = (from stu in t where stu.Id == v select stu).FirstOrDefault();
var grad = (from gradu in g where gradu.Id == v select gradu).FirstOrDefault();
return term.startdate > grad.ACAD_COMMENCEMENT_DATE.Value.AddDays(-14);
}
这种方法有更多的代码可以编写,但是当程序必须经过3000条左右的记录时,它会节省大量的时间。