有没有更快的方法来处理嵌套的 linq 查询?
is there a faster way to work with nested linq query?
我正在尝试使用嵌套 linq 查询来查询 table。我的查询有效但速度太慢。我有将近 400k 行。这个查询对 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# 语句编写了这个查询。
您正在迭代源集合 (YOKAktarim
) 三次,这使得您的查询成为 *O(n^3)` 查询。会很慢。
您可以简单地遍历 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()
调用即可解决您的问题。
对于 400K 条记录,您应该能够return将学生 ID 和部门 ID 放入内存列表中。
var list1 = (from r in YOKAktarim
group r by new { r.StudentID, r.DepartmentID} into g
select g.Key
).ToList();
获得此列表后,您应该可以按学生 ID 和 select 拥有多个记录的学生进行分组。
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 数据库一次,而不是数十万次。
我正在尝试使用嵌套 linq 查询来查询 table。我的查询有效但速度太慢。我有将近 400k 行。这个查询对 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# 语句编写了这个查询。
您正在迭代源集合 (YOKAktarim
) 三次,这使得您的查询成为 *O(n^3)` 查询。会很慢。
您可以简单地遍历 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()
调用即可解决您的问题。
对于 400K 条记录,您应该能够return将学生 ID 和部门 ID 放入内存列表中。
var list1 = (from r in YOKAktarim
group r by new { r.StudentID, r.DepartmentID} into g
select g.Key
).ToList();
获得此列表后,您应该可以按学生 ID 和 select 拥有多个记录的学生进行分组。
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 数据库一次,而不是数十万次。