最初我想询问查询Datatable中特定行的最快方法。
我已经测试了5种不同的方法,得出了一个令人惊讶的结果(对我来说)。
背景: 我在MS Sql-Server 2005数据库中创建了一个View。这个View目前有6318行。因为我必须经常检查给定的id是否存在于这个View中,所以我想知道最有效的方法是什么。我在一个强类型数据集中创建了一个DataAdapter,它返回所有行并填充一个Datatable。 我的第一种方法是创建一个共享的泛型List(of Int32),并在应用程序启动时将其填充到来自View的ID中。然后使用List.Contains检查当前ID是否在此列表中。由于所有行都是不同的,我想知道使用SortedList及其ContainsKey方法是否更快。 然后我还检查了直接访问Datatable的性能,包括其Select-Method、自动生成的(当列被定义为主键时)FindBy-method和最后一个DatarowCollection.Contains方法。 因此,我有5种方法来检查我的ID是否在该View(或映射的List/SortedList)中。我使用System.Diagnostics.StopWatch测试了它们的性能,并得到了一些有趣的结果。 我认为SortedList.ContainsKey必须比List.Contains更快,因为它们是不同的和排序的,但事实相反。 但对我来说最令人惊讶的是DataRowCollection.Contains方法(我先前忘记了)远远是最快的。 它甚至比dataTable.FindBy方法快50倍。
- 这些差异是由什么引起的?
- 我是否忘记了更好的方法?
- 我的测量方法是否正确(我认为最好循环它们并取那些值)?
- 这些值是否可转移或依赖于Datatable / Collection的大小?
- 在我的更新(1000000次迭代)之后,ContainsKey是最快的。 这是因为我总是检查相同的ID还是一般情况下? 是否有一种没有Dictionary KeyValue-Pair开销的SortedList?
结果 [1000000次迭代*]
- Timespan 1 = SortedList.ContainsKey = Ø 0.65634 [238.1095] ms
- Timespan 2 = List.Contains = Ø 0.06802 [57045.37955] ms
- Timespan 3 = DataTable.FindByIdData(auto-generated method) = Ø 0.31580 [1542.62345] ms
- Timespan 4 = DataTable.Select = Ø 0.27790 [26029.39635] ms
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"
UPDATE: I have changed my results and the source above. In squared brackets are the values for 1000000 iterations. Now the result is completely different. The fastest method now is definitely is the ContainsKey of the SortedList.
UPDATE 2: I forgot the alternative to use List.BinarySearch. This seems to be fastest for me:
clock.Start() For i As Int32 = 1 To 1000000 applies = listAC17NextClaims.BinarySearch(myClaim.idData) > -1 Next clock.Stop()
needs only 219.1805 ms to perform 1000000 iterations and hence is the fastest without the overhead of a SortedList-KeyValue-Pair. I can use it without to sort the list because the DataAdapter filled the datatable with an Order By clause.