Surpreendentes diferenças de desempenho: List.Constains, SortedList.ContainsKey, DataRowCollection.Contains, DataTable.Select, DataTable.FindBy

Originalmente, eu queria pedir a maneira mais rápida de consultar um Datatable para uma linha especial.

Eu testei 5 métodos diferentes para o desempenho deles com um resultado surpreendente (para mim).

Plano de fundo: Criei uma exibição em um banco de dados MS Sql-Server 2005. Esta visualização possui atualmente uma contagem total de 6318 linhas. Como devo verificar com muita frequência se um determinado ID existe nessa exibição, perguntei-me qual é a maneira mais eficiente de fazer. Criei um DataAdapter em um conjunto de dados fortemente tipado que retorna todas as linhas e preenche um Datatable. Minha primeira abordagem foi criar uma lista genérica compartilhada (do Int32) e preenchê-la com os IDs da exibição uma vez no início do aplicativo. Então useList.Contains para verificar se o ID atual está nesta lista. Como todas as linhas são distintas, perguntei-me se não seria mais rápido usar um SortedList e seuContainsKey-método. Depois verifiquei também o desempenho do acesso direto ao Datable com seusMétodo Select, é gerado automaticamente (quando a coluna é definida como chave primária)Método FindBy e por último mas não menos importante, oDatarowCollection.Contains-Método. Então, eu tenho 5 métodos para verificar se o meu ID está nessa exibição (ou mapeado List / SortedList).

Eu medi seu desempenho com oSystem.Diagnostics.StopWatch e obtive alguns resultados interessantes. Eu pensei que o SortedList.ContainsKey deve ser mais rápido que o List.Contains porque eles são distintos e classificados, mas o oposto é verdadeiro. Mas o mais surpreendente para mim foi que o DataRowCollection.Contains-Method (que eu havia esquecido) é de longe o mais rápido. É até 50 vezes mais rápido que o método dataTable.FindBy.

O que causou essas diferenças?Eu esqueci uma maneira melhor?Meu método de medição está correto (acho melhor eu fazer um loop e pegar esses valores)?Os valores são transferíveis ou dependem do tamanho da Datatable / Collection?Após a minha atualização (1000000 iterações), o ContainsKey é o mais rápido. Isso ocorre porque eu sempre procuro o mesmo ID ou em geral? Existe algum tipo de SortedList sem a sobrecarga do par de valores-chave de um dicionário?

Resultados [para 1000000 iterações *]

Período 1 =SortedList.ContainsKey = Ø 0,65634 [238.1095] SenhoraPeríodo 2 =List.Contains = Ø 0,06802 [57045.37955] SenhoraPeríodo 3 =DataTable.FindByIdData(método gerado automaticamente) = Ø 0,31580 [1542.62345] SenhoraPeríodo 4 =DataTable.Select = Ø 0,27790 [26029.39635] Senhora

Período 5 =DataRowCollection.Contains = Ø 0,00638 [1202.79735] Senhora

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

E por uma questão de completude, parte doFonte 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"

ATUALIZAR: Alterei meus resultados e a fonte acima. Entre colchetes, estão os valores para 1000000 iterações. Agora o resultado é completamente diferente. O método mais rápido agora é definitivamente o ContainsKey do SortedList.

ATUALIZAÇÃO 2: Esqueci a alternativa de usarList.BinarySearch. Isso parece ser mais rápido para mim:

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

precisa de apenas 219,1805 ms para executar 1000000 iterações e, portanto, é o mais rápido sem a sobrecarga de um par SortedList-KeyValue. Posso usá-lo sem classificar a lista porque o DataAdapter preencheu a tabela de dados com uma cláusula Order By.

questionAnswers(3)

yourAnswerToTheQuestion