我的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多个列,因此似乎出现了不同类型的集合 尴尬的比赛。
答案 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.