尽快找到DataTable中的匹配记录

时间:2018-12-04 16:52:15

标签: c#

我的C# <link data-require="bootstrap@*" data-semver="3.3.2" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" /> <script data-require="jquery@2.1.3" data-semver="2.1.3" src="https://code.jquery.com/jquery-2.1.3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.js"></script> <link data-require="ui-select@0.11.1" data-semver="0.11.1" rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/ui-select/v0.11.2/dist/select.css" /> <script data-require="ui-select@0.11.1" data-semver="0.11.1" src="https://cdn.rawgit.com/angular-ui/ui-select/v0.11.2/dist/select.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.default.css"> <script src="https://cdn.rawgit.com/angular-ui/ui-grid.info/v3.0.7/release/3.0.7/ui-grid.min.js"></script> <link rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/ui-grid.info/v3.0.7/release/3.0.7/ui-grid.min.css" type="text/css" /> 行非常多,在我的导入器应用程序中,必须在给定的导入中查询数十万次。因此,我正在尝试寻找最快的搜索方式。到目前为止,我对非常奇怪的结果感到困惑。首先,这是我正在尝试的2种不同方法:

方法1

DataTables

APPROACH#2

public static bool DoesRecordExist(string keyColumn, string keyValue, DataTable dt) {
 if (dt != null && dt.Rows.Count > 0) {
  return dt.Select($"{keyColumn} = '{SafeTrim(keyValue)}'").Count() > 0;
 } else {
  return false;
 }
}

在模拟测试中,我对每种方法运行15,000次,并提交硬编码数据。这是一个公平的考验。方法1大大加快了速度。但是在实际的应用执行中,方法1的运行速度慢得多

为什么会违反直觉?还有其他[更快速]的方法来查询我没有尝试过的数据表吗?

  

编辑:之所以使用数据表,而不是其他类型的   集合是因为​​我所有的数据源都是MySQL表或   CSV文件。因此,数据表似乎是一个合理的选择。其中一些   表格包含10多个列,因此似乎出现了不同类型的集合   尴尬的比赛。

3 个答案:

答案 0 :(得分:1)

如果您想更快地访问并且仍然希望坚持使用DataTable,请使用字典存储给定键的行号。在这里,我假设每个键在DataTable中都是唯一的。如果没有,则必须使用Dictionary<string, List<int>>Dictionary<string, HashSet<int>>来存储索引。

var indexes = new Dictionary<string, int>();
for (int i = 0; i < dt.Rows.Count; i++) {
    indexes.Add((string)dt.Rows[i].Column(keyColumn), i);
}

现在,您可以使用超快速方式访问行

var row = dt.Rows[indexes[theKey]];

答案 1 :(得分:0)

我有一个非常相似的问题,除了我需要匹配行的实际首次出现。

使用.Select.FirstOrDefault(方法1)需要38分钟才能运行。 使用.Where.FirstOrDefault(方法2)需要6分钟才能运行。

在类似的情况下,我不需要FirstOrDefault,而只需要查找和使用唯一匹配的记录,到目前为止,我发现最快的方法是使用HashTable,其中的键是组合值尝试匹配的任何列中的任意一个,并且值是数据行本身。寻找匹配几乎是瞬间。

函数是

 public Hashtable ConvertToLookup(DataTable myDataTable, params string[] pKeyFieldNames)
    {
        Hashtable myLookup = new Hashtable(StringComparer.InvariantCultureIgnoreCase);  //Makes the Key Case Insensitive
        foreach (DataRow myRecord in myDataTable.Rows)
        {
            string myHashKey = "";
            foreach (string strKeyFieldName in pKeyFieldNames)
            {
                myHashKey += Convert.ToString(myRecord[strKeyFieldName]).Trim();
            }

            if (myLookup.ContainsKey(myHashKey) == false)
            {
                myLookup.Add(myHashKey, myRecord);
            }
        }

        return myLookup;
    }

用法是...

//Build the Lookup Table
Hashtable myLookUp = ConvertToLookup(myDataTable, "Col1Name", "Col2Name");

//Use it
if (myLookUp.ContainsKey(mySearchForValue) == true)
{
  DataRow myRecord = (DataRow)myLookUp[mySearchForValue]);
}

答案 2 :(得分:0)

全部。答对了!想要分享为其他答案,只是因为我的上一篇文章可能适用于其他方法。在这种情况下,我能够从8分钟降至6秒,而无需使用任何一种方法...

同样,键是HashTable,或者在我的情况下是字典,因为我有多个记录。回顾一下,对于我来说,我需要从数据表中删除在另一数据表中找到的每条匹配记录的1行。最终,我的第一个数据表仅包含“丢失”记录。

这使用了其他功能...

    // -----------------------------------------------------------
    // Creates a Dictionary with Grouping Counts from a DataTable
    public Dictionary<string, Int32> GroupBy(DataTable myDataTable, params string[] pGroupByFieldNames)
    {
        Dictionary<string, Int32> myGroupBy = new Dictionary<string, Int32>(StringComparer.InvariantCultureIgnoreCase);  //Makes the Key Case Insensitive
        foreach (DataRow myRecord in myDataTable.Rows)
        {
            string myKey = "";
            foreach (string strGroupFieldName in pGroupByFieldNames)
            {
                myKey += Convert.ToString(myRecord[strGroupFieldName]).Trim();
            }

            if (myGroupBy.ContainsKey(myKey) == false)
            {
                myGroupBy.Add(myKey, 1);
            }
            else
            {
                myGroupBy[myKey] += 1;
            }
        }

        return myGroupBy;
    }

现在..说您有一个要用作基于Col1和Col2的“匹配值”的记录表

Dictionary<string, Int32> myQuickLookUpCount = GroupBy(myMatchTable, "Col1", "Col2");

现在是魔术。我们正在遍历您的主表,并为匹配表中的每个实例删除一个记录实例。这是使用方法2花费8分钟或使用方法1花费38分钟的部分。但是现在只需要几秒钟。

myDataTable.AcceptChanges(); //Trick that allows us to delete during a ForEach!
foreach (DataRow myDataRow in myDataTable.Rows)
{
   //Grab the Key Values
   string strKey1Value = Convert.ToString(myDataRow ["Col1"]);
   string strKey2Value = Convert.ToString(myDataRow ["Col2"]);

   if (myQuickLookUpCount.TryGetValue(strKey1Value + strKey2Value, out Int32 intTotalCount) == true && intTotalCount > 0)
   {
     myDataTable.Delete();  //Mark our Row to Delete
     myQuickLookUpCount [strKey1Value + strKey2Value ] -= 1;  //Decrement our Counter
    }
 }

 myDataTable.AcceptChanges(); //Commits our changes and actually deletes the rows.