首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >DataTable.AsEnumerable().Where() vs DataTable.Select()

DataTable.AsEnumerable().Where() vs DataTable.Select()
EN

Stack Overflow用户
提问于 2020-06-11 13:35:35
回答 2查看 1.8K关注 0票数 1

我们一直在Linq模式下查询DataTable中的数据,并且从来没有遇到过任何性能问题。在接下来的案例中,Linq使用600s+,但使用DataTable.Select()只需要3秒。结果是一致的。直觉告诉我,Linq不应该那么慢,我的操作有问题,但我不知道如何改进,有人能给我一些建议吗?

GetDtTest_Base()GetDtTest_Info()是通过ADO.NET中的SqlDataAdapter从Sql Server返回的DataTableDataSet

代码语言:javascript
运行
复制
DataTable dtBase = GetDtTest_Base();  //4W rows
DataSet dsInfo = GetDtTest_Info();    //two Datatable  4W rows, 2K rows

//Normally, we use Linq all the time. In this scenario, it takes about 600 seconds to query through Linq
foreach (DataRow item in dtBase.Rows)
{
    string pnum = item["pnum"].ToString();
    string number = item["number"].ToString();

    var query_Info1 = dsInfo.Tables[0].AsEnumerable()
        .Where(w => w.Field<string>("pnum") == pnum && w.Field<string>("calleee164") == number)
        .Select(s => s);
    item["conn"] = query_Info1.Count() > 0 ? (query_Info1.First())["conn"] : 0;
    item["total"] = query_Info1.Count() > 0 ? (query_Info1.First())["total"] : 0;

    var query_Info2 = dsInfo.Tables[1].AsEnumerable()
        .Where(w => w.Field<string>("pnum") == pnum && w.Field<string>("calleee164") == number)
        .Select(s => s);
    item["asCnt"] = query_Info2.Count() > 0 ? 1 : 0;
    item["asTrunks"] = query_Info2.Count() > 0 ? (query_Info2.First())["trunks"] : null;
}

//After changing this query, it only took 3 seconds to query
foreach (DataRow item in dtBase.Rows)
{
    string pnum = item["pnum"].ToString();
    string number = item["number"].ToString();

    DataRow[] query_Info1 = dsInfo.Tables[0].Select($"pnum='{pnum}' and calleee164='{number}'");
    if (query_Info1 != null && query_Info1.Length >= 1)
    {
        item["conn"] = query_Info1[0]["conn"].ToString();
        item["total"] = query_Info1[0]["total"].ToString();
    }
    else
    {
        item["conn"] = 0;
        item["total"] = 0;
    }

    DataRow[] query_Info2 = dsInfo.Tables[1].Select($"pnum='{pnum}' and calleee164='{number}'");
    if (query_Info2 != null && query_Info2.Length >= 1)
    {
        item["asCnt"] = 1;
        item["asTrunks"] = query_Info2[0]["trunks"].ToString();
    }
    else
    {
        item["asCnt"] = 0;
        item["asTrunks"] = null;
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-11 14:37:21

另一种方法是创建一个为查找而设计的结构。

最初的方法将为dtBase中的每一行迭代dsInfo表,这是O(n*m)。使用查找数据结构,从dsInfo表中查找行将是一个操作,这使得O(n)。

代码语言:javascript
运行
复制
var base = GetDtTest_Base();
var infoSet = GetDtTest_Info();

var firstLookup = info[0].AsEnumerable()
    .ToLookup(row => (Num: row.Field<string>("pnum"), Callee: row.Field<string>("calleee164")));
var secondLookup = info[1].AsEnumerable()
    .ToLookup(row => (Num: row.Field<string>("pnum"), Callee: row.Field<string>("calleee164")));

foreach (DataRow item in dtBase.Rows)
{
    var pnum = item["pnum"].ToString();
    var number = item["number"].ToString();
    var key = (Num: pnum, Callee: number);

    item["conn"] = firstLookup[key].Select(row => row.Field<int>("conn")).FirstOrDefault();
    item["total"] = firstLookup[key].Select(row => row.Field<int>("total")).FirstOrDefault();

    item["asCnt"] = secondLookup[key].Any() ? 1 : 0;
    item["asTrunks"] = secondLookup[key].Select(row => row.Field<string>("trunks")).FirstOrDefault();
}
票数 3
EN

Stack Overflow用户

发布于 2021-04-13 09:27:41

有点严肃的挖掘,但最近在旧代码中遇到了DataTable.AsEnumerable()...的性能问题,这些问题通过转换到DataTable.AsEnumerable().ToList()...得到了解决。

Fabio的答案是+1,这绝对是一种更简洁、更高效的方法,但是如果你不想过多地处理遗留代码,并且分析会在你的linq查询中显示一个热路径,那么尝试将其转换为列表,看看效果如何。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62317744

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档