我正在尝试使用嵌套的linq查询来查询一个表。我的查询正在工作,但速度太慢。我有将近40万排。这个查询在1000行中工作10秒。对于400k,我认为大约需要2个小时。
我有这样的行
StudentNumber - DepartmentID
n100 - 1
n100 - 1
n105 - 1
n105 - 2
n107 - 1
我想要不同系ID的学生。我的成绩是这样的。
StudentID - List
n105 - 1 2
我的查询提供了它。但速度很慢。
var sorgu = (from yok in YOKAktarim
group yok by yok.StudentID into g
select new {
g.Key,
liste=(from birim in YOKAktarim where birim.StudentID == g.Key select new { birim.DepartmentID }).ToList().GroupBy (x => x.DepartmentID).Count()>1 ? (from birim in YOKAktarim where birim.StudentID == g.Key select new { birim.DepartmentID }).GroupBy(x => x.DepartmentID).Select(x => x.Key).ToList() : null,
}).Take(1000).ToList();
Console.WriteLine(sorgu.Where (s => s.liste != null).OrderBy (s => s.Key));
我用linqpad C#语句编写了这个查询。
对于400K记录,您应该能够将学生ID和部门ID返回到内存列表中。
var list1 = (from r in YOKAktarim
group r by new { r.StudentID, r.DepartmentID} into g
select g.Key
).ToList();
一旦你有了这个列表,你就可以按学生ID分组,并选择那些有多个记录的学生。
var list2 = (from r in list1 group r by r.StudentID into g
where g.Count() > 1
select new
{
StudentID = g.Key,
Departments = g.Select(a => a.DepartmentID).ToList()
}
).ToList();
这应该更快,因为它只访问sql数据库一次,而不是数十万次。
您正在迭代源集合(YOKAktarim
)三次,这使得您的查询*O(n^3)`query。它会很慢。
您可以简单地对g
进行迭代,而不是返回到源集合来获取组的内容。
var sorgu = (from yok in YOKAktarim
group yok by yok.StudentID into g
select new {
g.Key,
liste = from birim in g select new { birim.DepartmentID }).ToList().GroupBy (x => x.DepartmentID).Count()>1 ? (from birim in g select new { birim.DepartmentID }).GroupBy(x => x.DepartmentID).Select(x => x.Key).ToList() : null,
}).Take(1000).ToList();
然而,这仍然不是最佳的,因为你正在做很多冗余的子分组。您的查询相当于:
from yok in YOKAktarim
group yok by yok.StudentID into g
let departments = g.Select(g => g.DepartmentID).Distinct().ToList()
where departments.Count() > 1
select new {
g.Key,
liste = departments
}).Take(1000).ToList();
我无法证明这个怪物的正确性,但只需删除除最外层调用之外的所有ToList()
调用就可以解决问题。