Reputation: 2125
I have a huge DataTable, and I need go by each row and validate an specific value.
Which method give me more performance, an structure of IF ELSE or SELECT CASE? (I'm focused in the method that offer me the best performance)
IF ELSE (METHOD #1)
For Each vRow In vDTtemp.Rows
If vRow("Item") = "Time" Then
vRow("Result") = "000"
ElseIf vRow("Item") = "DateTime" Then
vRow("Result") = "001"
ElseIf vRow("Item") = "String" Then
vRow("Result") = "002"
Else
vRow("Result") = "N/A"
End If
Next
SELECT CASE (METHOD #2)
For Each vRow In vDTtemp.Rows
Select Case vRow("Item")
Case "Time"
vRow("Result") = "000"
Case "DateTime"
vRow("Result") = "001"
Case "String"
vRow("Result") = "002"
Case Else
vRow("Result") = "N/A"
End Select
Next
Upvotes: 6
Views: 26507
Reputation: 73
Ok... it was long time ago for this post, but now i was searching the same question and i can add new optimization for this. For now i've choosed to use the select case, for be more readable. In the other hand, the performance decreases a lot when a "Dim" is inside a for-next loop.
For Each vRow In vDTtemp.Rows
-------> Dim rowItem = vRow("Item")
If rowItem = "Time" Then
vRow("Result") = "000"
ElseIf rowItem = "DateTime" Then
vRow("Result") = "001"
ElseIf rowItem = "String" Then
vRow("Result") = "002"
Else
vRow("Result") = "N/A"
End If
Next
It's a lot faster when dim is oitside even if you want to use the if-then structure:
-------> Dim rowItem as string
For Each vRow In vDTtemp.Rows
-------> rowitem= vRow("Item")
If rowItem = "Time" Then
vRow("Result") = "000"
ElseIf rowItem = "DateTime" Then
vRow("Result") = "001"
ElseIf rowItem = "String" Then
vRow("Result") = "002"
Else
vRow("Result") = "N/A"
End If
Next
I hope this be helpful for someone more ;)
Upvotes: 5
Reputation: 198
I've spent quite a lot of time working on this same problem over the last couple of days and have found one approach which is much faster than the others. I too found that using Select Case on a string variable was equivalent to a series of If/Else If statements, and both were disappointingly slow.
However the following technique has worked very well, and reduced the amount of time by over 50%. Instead of the original code:
For Each vRow In vDTtemp.Rows
Select Case vRow("Item")
Case "Time"
vRow("Result") = "000"
Case "DateTime"
vRow("Result") = "001"
Case "String"
vRow("Result") = "002"
Case Else
vRow("Result") = "N/A"
End Select
Next
Change it around to switch on a simple Boolean, and use the String.Equals method, like this:
For Each vRow In vDTtemp.Rows
'Read out the row value so we only need to access the datarow once
rowValue = vRow("Item")
'Which of these statements is true?
Select Case True
Case rowValue.Equals("Time")
vRow("Result") = "000"
Case rowValue.Equals("DateTime")
vRow("Result") = "001"
Case rowValue.Equals("String")
vRow("Result") = "002"
Case Else
vRow("Result") = "N/A"
End Select
Next
I've had significant improvements by approaching it in this way, in one case reducing my code from 1.3 seconds over a 100,000 iteration loop to 0.5 seconds. If this is in a really frequently-called time-critical section of code, that can make a big difference.
As pointed out in the comments below however, this performs an "Ordinal" comparison of strings, which may not result in the expected behaviour if non-English locales are being used (see the comments for examples).
Adam.
Upvotes: 5
Reputation: 941635
It makes no difference, both code styles generate the exact same IL. Something you can see by running the ildasm.exe tool on your compiled assembly.
In general, the VB.NET compiler does make an effort to optimize a Select statement. That will work when it uses a simple value type as the selector and trivial Case statements. The generated code will use a dedicated IL instruction, Opcodes.Switch. Which will be compiled to machine code that uses a lookup table. Very fast.
That however doesn't work when you use a string expression as the selector. Making a lookup table for that one would require the equivalent of a dictionary of delegates. That's too impactful, the compiler cannot do anything but convert each case statement to the equivalent of an If statement. You can however optimize it yourself easily by creating this Dictionary in your code, easy to do since the dictionary key and value are just simple strings. You don't have enough cases and the strings are too short to make this pay off majorly, although it is worth a try. It certainly can compact your code.
Upvotes: 6
Reputation: 10398
If you really find this is your bottleneck in performance, you could try modifying the If..Then clause as follows to only access the indexer once:
For Each vRow In vDTtemp.Rows
Dim rowItem = vRow("Item")
If rowItem = "Time" Then
vRow("Result") = "000"
ElseIf rowItem = "DateTime" Then
vRow("Result") = "001"
ElseIf rowItem = "String" Then
vRow("Result") = "002"
Else
vRow("Result") = "N/A"
End If
Next
That being said, I suspect each of these is a case of over optimizing. The compiler should to the best thing here. If you check the IL from a long Select Case, you may find that it uses a string of If..then clauses under the covers with "goto" to escape the rest of the clauses. Your best option here is to get the most maintainable code as the performance benefits you may gain will be offset by the minimal boost you may see between if..then and select case.
Upvotes: 2