编程语言
首页 > 编程语言> > c# – 搜索可枚举的最有效方法

c# – 搜索可枚举的最有效方法

作者:互联网

我正在编写一个小程序,它接收一个.csv文件作为输入,大约有45k行.我试图将此文件的内容与数据库中的表的内容进行比较(SQL Server通过动态CRM使用Xrm.Sdk,如果它有所不同).

在我当前的程序中(需要大约25分钟进行比较 – 文件和数据库完全相同,这两个45k行没有差别),我在数据库中的所有现有记录都在DataCollection< Entity>继承Collection< T>和IEnumerable< T>

在我下面的代码中,我使用Where方法进行过滤,然后根据匹配计数进行逻辑. Where似乎是这里的瓶颈.有没有比这更有效的方法?我绝不是LINQ专家.

foreach (var record in inputDataLines)
{
    var fields = record.Split(',');

    var fund = fields[0];
    var bps = Convert.ToDecimal(fields[1]);
    var withdrawalPct = Convert.ToDecimal(fields[2]);
    var percentile = Convert.ToInt32(fields[3]);
    var age = Convert.ToInt32(fields[4]);
    var bombOutTerm = Convert.ToDecimal(fields[5]);

    var matchingRows = existingRecords.Entities.Where(r => r["field_1"].ToString() == fund
                                      && Convert.ToDecimal(r["field_2"]) == bps
                                      && Convert.ToDecimal(r["field_3"]) == withdrawalPct
                                      && Convert.ToDecimal(r["field_4"]) == percentile
                                      && Convert.ToDecimal(r["field_5"]) == age);

    entitiesFound.AddRange(matchingRows);

    if (matchingRows.Count() == 0)
    {
        rowsToAdd.Add(record);
    }
    else if (matchingRows.Count() == 1)
    {
        if (Convert.ToDecimal(matchingRows.First()["field_6"]) != bombOutTerm)
        {
            rowsToUpdate.Add(record);
            entitiesToUpdate.Add(matchingRows.First());
        }
    }
    else
    {
        entitiesToDelete.AddRange(matchingRows);
        rowsToAdd.Add(record);
    }
}

编辑:在执行此代码之前,我可以确认所有现有记录都在内存中.上述循环中没有IO或DB访问权限.

解决方法:

Himbrombeere是正确的,您应首先执行查询并将结果放入集合中,然后再使用Any,Count,AddRange或任何方法再次执行查询.在您的代码中,查询可能在每次循环迭代中执行5次.

请注意文档中的延迟执行一词.如果以这种方式实现方法,则意味着此方法可用于构造LINQ查询(因此您可以使用其他方法链接它,最后您有查询).但是,只有不使用延迟执行的方法(如Count,Any,ToList(或简单的foreach))才会实际执行它.如果您不希望每次执行整个查询并且您必须多次访问此查询,则最好将结果存储在集合中(.f.e with ToList).

但是,你可以使用一种效率更高的不同方法,Lookup< TKey,TValue>它类似于字典,可以与匿名类型一起使用作为键:

var lookup = existingRecords.Entities.ToLookup(r => new 
{
    fund = r["field_1"].ToString(),
    bps = Convert.ToDecimal(r["field_2"]),
    withdrawalPct =  Convert.ToDecimal(r["field_3"]),
    percentile = Convert.ToDecimal(r["field_4"]),
    age = Convert.ToDecimal(r["field_5"])
});

现在,您可以非常有效地在循环中访问此查找.

foreach (var record in inputDataLines)
{
    var fields = record.Split(',');
    var fund = fields[0];
    var bps = Convert.ToDecimal(fields[1]);
    var withdrawalPct = Convert.ToDecimal(fields[2]);
    var percentile = Convert.ToInt32(fields[3]);
    var age = Convert.ToInt32(fields[4]);
    var bombOutTerm = Convert.ToDecimal(fields[5]);

    var matchingRows = lookup[new {fund, bps, withdrawalPct, percentile, age}].ToList();

    entitiesFound.AddRange(matchingRows);

    if (matchingRows.Count() == 0)
    {
        rowsToAdd.Add(record);
    }
    else if (matchingRows.Count() == 1)
    {
        if (Convert.ToDecimal(matchingRows.First()["field_6"]) != bombOutTerm)
        {
            rowsToUpdate.Add(record);
            entitiesToUpdate.Add(matchingRows.First());
        }
    }
    else
    {
        entitiesToDelete.AddRange(matchingRows);
        rowsToAdd.Add(record);
    }
}

请注意,即使密钥不存在(返回空列表),这也会起作用.

标签:c,linq,dynamics-crm,performance,processing-efficiency
来源: https://codeday.me/bug/20190722/1500864.html