最初我想问一下查询Datatable的特殊行的最快方法。
我已经为他们的表现测试了5种不同的方法,结果令人惊讶(对我而言)。
背景: 我在MS Sql-Server 2005数据库中创建了一个View。此视图当前总计数为6318行。因为我必须经常检查这个视图中是否存在给定的id,我想知道什么是最有效的方法。我在强类型数据集中创建了一个DataAdapter,它返回所有行并填充数据表。 我的第一种方法是创建一个共享的通用List(Int32),并在应用程序启动时用视图中的ID填充它。然后使用List.Contains检查当前ID是否在此列表中。因为所有行都是不同的,我想知道使用SortedList及其ContainsKey - metod是否更快。 然后我还检查了使用Select-Method直接访问Datable的性能,它是自动生成的(当列被定义为主键时)FindBy-method,最后但并非最不重要的是DatarowCollection.Contains - 方法。 所以我有5个方法来检查我的ID是否在该视图中(或映射的List / SortedList)。
我用System.Diagnostics.StopWatch测量了他们的表现并获得了一些有趣的结果。我认为SortedList.ContainsKey必须比List.Contains更快,因为它们是不同的并且已经排序,但反之亦然。 但对我来说最令人惊讶的是DataRowCollection.Contains-Method(我第一次忘记了)是迄今为止最快的。它甚至比dataTable.FindBy方法快50倍。
结果 [适用于1000000次迭代*]
Timespan 5 = DataRowCollection.Contains =Ø0.00638[ 1202.79735 ] ms
1.)
Timespan 1: 0,6913 ms
Timespan 2: 0,1053 ms
Timespan 3: 0,3279 ms
Timespan 4: 0,1002 ms
Timespan 5: 0,0056 ms
2.)
Timespan 1: 0,6405 ms
Timespan 2: 0,0588 ms
Timespan 3: 0,3112 ms
Timespan 4: 0,3872 ms
Timespan 5: 0,0067 ms
3.)
Timespan 1: 0,6502 ms
Timespan 2: 0,0588 ms
Timespan 3: 0,3092 ms
Timespan 4: 0,1268 ms
Timespan 5: 0,007 ms
4.)
Timespan 1: 0,6504 ms
Timespan 2: 0,0586 ms
Timespan 3: 0,3092 ms
Timespan 4: 0,3893 ms
Timespan 5: 0,0063 ms
5.)
Timespan 1: 0,6493 ms
Timespan 2: 0,0586 ms
Timespan 3: 0,3215 ms
Timespan 4: 0,386 ms
Timespan 5: 0,0063 ms
Timespan 1: 0,6913 0,6405 0,6502 0,6504 0,6493 = Ø 0,65634
Timespan 2: 0,1053 0,0588 0,0588 0,0586 0,0586 = Ø 0,06802
Timespan 3: 0,3279 0,3112 0,3092 0,3092 0,3215 = Ø 0,31580
Timespan 4: 0,1002 0,3872 0,1268 0,3893 0,3860 = Ø 0,27790
Timespan 5: 0,0056 0,0067 0,0070 0,0063 0,0063 = Ø 0,00638
为了完整性, VB.Net源:
的一部分Dim applies As Boolean
Dim clock As New System.Diagnostics.Stopwatch
clock.Start()
For i As Int32 = 1 To 1000000
applies = sortedListAC17NextClaims.ContainsKey(myClaim.idData)
Next
clock.Stop()
Dim timeSpan1 As String = "Timespan 1: " & clock.Elapsed.TotalMilliseconds.ToString & " ms"
clock.Reset()
clock.Start()
For i As Int32 = 1 To 1000000
applies = listAC17NextClaims.Contains(myClaim.idData)
Next
clock.Stop()
Dim timeSpan2 As String = "Timespan 2: " & clock.Elapsed.TotalMilliseconds.ToString & " ms"
clock.Reset()
clock.Start()
For i As Int32 = 1 To 1000000
applies = Not MyDS.AC17NextClaims.FindByIdData(myClaim.idData) Is Nothing
Next
clock.Stop()
Dim timeSpan3 As String = "Timespan 3: " & clock.Elapsed.TotalMilliseconds.ToString & " ms"
clock.Reset()
clock.Start()
For i As Int32 = 1 To 1000000
applies = MyDS.AC17NextClaims.Select("idData=" & myClaim.idData).Length > 0
Next
clock.Stop()
Dim timeSpan4 As String = "Timespan 4: " & clock.Elapsed.TotalMilliseconds.ToString & " ms"
clock.Reset()
clock.Start()
For i As Int32 = 1 To 1000000
applies = MyDS.AC17NextClaims.Rows.Contains(myClaim.idData)
Next
clock.Stop()
Dim timeSpan5 As String = "Timespan 5: " & clock.Elapsed.TotalMilliseconds.ToString & " ms"
更新 我已经改变了我的结果和上面的来源。方括号中是1000000次迭代的值。现在结果完全不同了。现在最快的方法肯定是SortedList的ContainsKey。
更新2: 我忘记了使用List.BinarySearch的替代方法。 这似乎对我来说最快:
clock.Start()
For i As Int32 = 1 To 1000000
applies = listAC17NextClaims.BinarySearch(myClaim.idData) > -1
Next
clock.Stop()
仅需要219.1805 ms来执行1000000次迭代,因此在没有SortedList-KeyValue-Pair的开销的情况下是最快的。 我可以在不对列表进行排序的情况下使用它,因为DataAdapter使用Order By子句填充数据表。
答案 0 :(得分:5)
在我看来,你并没有提供足够的工作来获得有用的时间。你的所有时间都是亚毫秒级,几乎可以肯定只是噪音 - 缓存,静音,抢先等等。
让你的收藏大得足以花费几秒钟来运行,或者至少在紧密的循环中运行每次测试足够的时间来花费几秒钟。
答案 1 :(得分:5)
为什么不使用具有HashTable作为基础数据结构(Dictionary<TKey, TValue>
或HashSet<T>
)的集合?如果密钥中没有冲突(如您所述),则HashTables
应提供O(1)
查找时间,并且不需要“排序”的开销。
编辑:如果仅想要存储密钥,则应使用.NET 3.5及更高版本中提供的HashSet<T>。
SortedList上的对SortedList对象的操作倾向于 要比a上的操作慢 Hashtable对象因为 排序。
要定位.NET 2.0,您可以自己滚动或使用Wintellect's Power Collections之类的预构建版本(您也可以轻松地使用源代码)。
答案 2 :(得分:0)
如前所述,您的代码只运行一次操作。通常的策略是多次运行代码(例如,执行3次搜索)以获得更大的数字(因此,如果3次搜索需要0.9秒,则可以说搜索需要0.3)。然后循环几次以允许您计算平均值(如果您愿意,包括标准差,过滤掉野性结果),然后在此之上运行一次而不注意记录时间以便任何JITing被执行。
此外,在发布模式下运行代码,不附加调试器。