代码之家  ›  专栏  ›  技术社区  ›  Tim Schmelter

令人惊讶的性能差异:List.Constains、SortedList.ContainsKey、DataRowCollection.Contains、DataTable.Select、DataTable.FindBy

  •  6
  • Tim Schmelter  · 技术社区  · 14 年前

    最初,我想寻求最快的方法来查询Datatable中的一个特殊行。

    我测试了5种不同方法的性能,结果令人惊讶。

    背景: 我在mssqlserver2005数据库中创建了一个视图。此视图当前共有6318行。因为我必须经常检查这个视图中是否存在给定的id,所以我想知道最有效的方法是什么。我在强类型数据集中创建了一个DataAdapter,它返回所有行并填充一个Datatable。 List.Contains 检查当前ID是否在此列表中。因为所有的行都是不同的,我想知道使用SortedList和它的 ContainsKey 然后我还检查了直接访问数据表的性能 Select-Method ,它将自动生成(当列定义为主键时) FindBy-method 最后但并非最不重要的是 DatarowCollection.Contains -方法。

    我用一个标准来衡量他们的表现 System.Diagnostics.StopWatch 但最让我吃惊的是DataRowCollection.Contains方法(我第一次忘记了)是迄今为止最快的。它甚至比dataTable.FindBy-method快50倍。

    1. 是什么导致了这些差异?
    2. 我忘了更好的方法吗?
    3. 值是可传输的还是依赖于数据表/集合的大小?
    4. 在我的更新(1000000次迭代)之后,ContainsKey是最快的。这是因为我总是检查相同的身份证还是一般的?有没有一种没有字典键值对开销的SortedList?

    结果 [对于1000000次迭代*]

    • 时间跨度1= SortedList.ContainsKey 238.1095 ]微软
    • 列表。包含 57045.37955
    • 时间跨度3= DataTable.FindByIdData (自动生成法)=0.31580[ 1542.62345 ]微软
    • DataTable.Select = 0.27790 [ 26029.39635
    • DataRowCollection.Contains = 0.00638 [ ]微软

      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次迭代的值。现在结果完全不同了。现在最快的方法肯定是分类列表的ContainsKey。

    • 我忘了另一种选择 List.BinarySearch

      clock.Start()
      For i As Int32 = 1 To 1000000
          applies = listAC17NextClaims.BinarySearch(myClaim.idData) > -1
      Next
      clock.Stop()
      

      只需要219.1805ms就可以执行1000000次迭代,因此在没有SortedList键值对开销的情况下是最快的。 我可以不用它来排序列表,因为DataAdapter用orderby子句填充了datatable。

    3 回复  |  直到 14 年前
        1
  •  5
  •   TheCloudlessSky    14 年前

    你为什么不用一个有 HashTable Dictionary<TKey, TValue> HashSet<T> )? HashTables 应提供 O(1)

    编辑:如果你 只有 HashSet<T>

    From MSDN 在SortedList上:

    对SortedList对象的操作 比在一台计算机上的操作慢 哈希表对象,因为

    要瞄准.NET2.0,您可以自己开发或使用一个预构建的,如 Wintellect's Power Collections

        2
  •  5
  •   Will Dean    14 年前

    在我看来,你提供的工作几乎不足以获得有用的时间安排。所有的时间都是亚毫秒级的,几乎可以肯定只是噪声缓存、jit-ing、抢占等。

        3
  •  0
  •   Adam Houldsworth    14 年前

    如前所述,代码只运行一次操作。通常的策略是多次运行代码(例如,执行3次搜索)以获得更大的数字(因此,如果3次搜索需要0.9秒,则可以说一次搜索需要0.3秒)。然后循环几次,让您计算一个平均值(包括标准偏差,如果您愿意的话,可以过滤掉不确定的结果),然后在此基础上,运行一次,而不必注意记录时间,以便执行任何JITing。

    另外,在没有附加调试器的情况下以发行模式运行代码。