针对大型数据集的高效LINQ查询
本文关键字:高效 LINQ 查询 数据集 大型 | 更新日期: 2023-09-27 17:58:13
我有一个LINQ查询,它在有500000多条记录的数据表上运行。这个查询只返回一行,但运行起来几乎需要30秒。这是我的查询
var callDetailsForNodes = from records in dtRowForNode.Select().Select(dr =>
new
{
caller1 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F1"] : dr["F2"],
caller2 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F2"] : dr["F1"],
time = dr["F3"],
filters = dr.Field<string>("F9")
}).Where(dr => (dtMin <= Convert.ToDateTime(dr.time)) && (dtMax >= Convert.ToDateTime(dr.time)) && (lstCallType.Contains(dr.filters))
&& (dtMinTime <= Convert.ToDateTime(dr.time).TimeOfDay) && (dtMaxTime >= Convert.ToDateTime(dr.time).TimeOfDay))
.GroupBy(drg => new { drg.caller1, drg.caller2 })
.Select(drg => new { drg.Key.caller1, drg.Key.caller2, count = drg.Count() }).AsEnumerable()
where (records.caller1.ToString() == VerSelected || records.caller2.ToString() == VerSelected)
select records;
我再次运行一个查询来重新排列数据,从上面的查询中获取数据作为
var callDetailsForNodes_ReArrange = from records in callDetailsForNodes.Select(r => new
{
caller1 = r.caller1.ToString() == VerSelected ? r.caller1 : r.caller2,
caller2 = r.caller1.ToString() != VerSelected ? r.caller1 : r.caller2,
count = r.count
})
select records;
然后我只是将这个集合绑定到gridview。有什么有效的方法可以在这么大的数据集上查询吗
编辑
我试着一步一步地调试程序,发现这两个查询实际上运行得很快,当我将这个查询的结果集添加到ObservableCollection以将其绑定到gridview时,这一步需要花费时间。这是代码
foreach (var callDetailsForNode_ReArrange in callDetailsForNodes_ReArrange)
{
_CallForNodes.Add(new CallForNodeData
{
Caller1 = callDetailsForNode_ReArrange.caller1.ToString(),
Caller2 = callDetailsForNode_ReArrange.caller2.ToString(),
Count = callDetailsForNode_ReArrange.count
});
}
此处调用DetailsForNodes_ReArrange的结果集计数=1
有一件事会有所帮助,那就是在调用之前将dtMin、dtMax和dtMinTime转换为数据单位(dr.time)。然后你就可以去掉convert了。ToDateTime,在每个记录上发生多次。
我已经稍微整理了一下您的查询(尽管这不会对性能产生很大影响,而且可能会有拼写错误,因为我手头没有VS)。从您的编辑来看,您似乎对LINQ中的延迟执行有点困惑。callDetailsForNodes
并不代表您的结果,它是一个一旦执行就会提供结果的查询。
如果您必须在过程中进行所有这些查询,我建议您在第一次选择后添加一个ToList
,并单独运行它。然后将ToList
添加到Where
子句中。调用ToList
将强制执行查询,您将看到延迟的位置。
最后一点需要注意的是,您应该将记录直接传递给ObservableCollection
构造函数,而不是为每个项调用Add
。调用Add
会(我认为)导致集合发出更改通知,这对小列表来说不是什么大不了的事情,但对大列表来说会减慢速度。
var callDetailsForNodes = dtRowForNode.AsEnumerable()
.Select(dr => new {
caller1 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F1"] : dr["F2"],
caller2 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F2"] : dr["F1"],
time = Convert.ToDateTime(dr["F3"]),
filters = dr.Field<string>("F9")})
.Where(dr => (dtMin <= dr.time)
&& (dtMax >= dr.time)
&& (lstCallType.Contains(dr.filters))
&& (dtMinTime <= dr.time.TimeOfDay)
&& (dtMaxTime >= dr.time.TimeOfDay)
&& caller1 == VerSelected || caller2 == VerSelected))
.GroupBy(drg => new { drg.caller1, drg.caller2 })
.Select(drg => new { drg.Key.caller1, drg.Key.caller2, count = drg.Count());