String.Equals Performance Comparison


I recently had an app that I used the VSTS Profiler on to find that a significant portion of time was spent comparing some long strings.  I was using String.Equals(string a, string b, StringComparison.InvariantCultureIgnoreCase) since I didn’t care about case or culture.  I switched to using OrdinalIgnoreCase and got a huge 5x performance gain!  So that begged the question, just how long do the various string comparison algorithms comparatively take?

OrdinalIgnoreCase was the fastest.  Ordinal was almost 2x as long.  The others were about 5x the cost.

The “==” operator (“a” == “b”) uses Ordinal by default.  So if case sensitivity isn’t an issue, you can get a 2x performance gain by using OrdinalIgnoreCase.

To perform the calculation: Comparing strings 200 characters in length made up of random characters 4,000,000 times with each of the StringComparison values, all done 4 times and averaged.  On a 1.8GHz Dell D610 w/ 2GB RAM using .NET 3.5 Beta2.  Download StringComparisonTest.zip

References

Comments (8)

  1. Rick Preston says:

    In previous versions, string.Compare(string, string, bool) could be used to perform case-insensitive comparisons. The MSDN docs for that method state:

    "The comparison uses the current culture to obtain culture-specific information such as casing rules and the alphabetic order of individual characters. "

    Underneath the covers, what is the string-string-bool method doing? Does it map itself to one of the StringComparison enums?

  2. I looked at the code using Reflector:

    public static int Compare(string strA, string strB, bool ignoreCase)

    {

       if (ignoreCase)

       {

           return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);

       }

       return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);

    }

  3. Anthony Borton on Can’t delete files from Document Library. Noad Coad on String.Equals Performance Comparison….

  4. ratkiley says:

    I was reading about the performance impacting overhead that the VB runtime library’s loose comparisons of differing data-types.

    http://www.ayende.com/Blog/archive/2005/12/22/8024.aspx

    I created a similar set of tests, in a console application, and came up with interesting results (see the attached zip file for the project source).   It turns out that [b]If ("" = String.Empty)[/b] is the least efficient method for comparison.  [b]If ("" = String.Empty)[/b]  is more than 20 times slower than [b]If ("" is Nothing)[/b].  None of the comparisons even approach the order of magnitude of the time involved in retrieving data from a remote database server, but if comparisons are used in library code which is referenced throughout a server application with a large number of concurrent users, the performance impacts can add up (like a high volume web application).  

    The tests results are ordered from least efficient to most efficient:

    [code]

    Comparing an empty string:

     If ("" = String.Empty) :              0.000121609375000 milliseconds

     If ("" = Nothing) :                   0.000009093750000 milliseconds

     If ("" = "") :                        0.000008296875000 milliseconds

     If (String.IsNullOrEmpty("")) :       0.000006781250000 milliseconds

     If ("".Length = 0) :                  0.000006515625000 milliseconds

     If ("" Is Nothing) :                  0.000005640625000 milliseconds

    Comparing a string with 100 characters:

     If ("" = String.Empty) :              0.000121921875000 milliseconds

     If ("" = Nothing) :                   0.000009109375000 milliseconds

     If ("" = "") :                        0.000008312500000 milliseconds

     If (String.IsNullOrEmpty("")) :       0.000006765625000 milliseconds

     If ("".Length = 0) :                  0.000006500000000 milliseconds

     If ("" Is Nothing) :                  0.000005656250000 milliseconds

    [/code]  

    Source code:

    [code]

    Module TestModule

    Private Const oneThousand As Double = 1000D

    Private Const oneBillionInteger As Integer = 1000000000

    Private Const oneBillionDouble As Double = 1000000000D

    Private Const empty As String = ""

    Private Const longString As String = "                                                                                          "

    Sub Main()

    ‘Dim d As Double = 0.000000009063196

    ‘Console.WriteLine(d.ToString("f15"))

    ‘Exit Sub

    Console.WriteLine("Comparing an empty string:")

    StringEqualsStringDotEmpty(empty)

    StringEqualsNothing(empty)

    StringEqualsString(empty)

    StringDotIsNullOrEmpty(empty)

    StringDotLengthEqualsZero(empty)

    StringIsNothing(empty)

    Console.WriteLine()

    Console.WriteLine("Comparing a string with 100 characters:")

    StringEqualsStringDotEmpty(longString)

    StringEqualsNothing(longString)

    StringEqualsString(longString)

    StringDotIsNullOrEmpty(longString)

    StringDotLengthEqualsZero(longString)

    StringIsNothing(longString)

    End Sub

    Private Sub StringEqualsString(ByVal input As String)

    Dim start As DateTime

    Dim elapsed As TimeSpan

    Dim str As String = ""

    start = DateTime.Now

    For i As Integer = 0 To oneBillionInteger

    If (str = "") Then

    End If

    Next i

    elapsed = DateTime.Now – start

    Console.WriteLine("  If ("""" = """") :" + vbTab + vbTab + vbTab + (elapsed.TotalMilliseconds / oneBillionDouble).ToString("f15") + " milliseconds")

    End Sub

    Private Sub StringDotLengthEqualsZero(ByVal input As String)

    Dim start As DateTime

    Dim elapsed As TimeSpan

    Dim str As String = ""

    start = DateTime.Now

    For i As Integer = 0 To oneBillionInteger

    If (str.Length = 0) Then

    End If

    Next i

    elapsed = DateTime.Now – start

    Console.WriteLine("  If ("""".Length = 0) :" + vbTab + vbTab + vbTab + (elapsed.TotalMilliseconds / oneBillionDouble).ToString("f15") + " milliseconds")

    End Sub

    Private Sub StringEqualsStringDotEmpty(ByVal input As String)

    Dim start As DateTime

    Dim elapsed As TimeSpan

    Dim str As String = ""

    start = DateTime.Now

    For i As Integer = 0 To oneBillionInteger

    If (str = String.Empty) Then

    End If

    Next i

    elapsed = DateTime.Now – start

    Console.WriteLine("  If ("""" = String.Empty) :" + vbTab + vbTab + (elapsed.TotalMilliseconds / oneBillionDouble).ToString("f15") + " milliseconds")

    End Sub

    Private Sub StringDotIsNullOrEmpty(ByVal input As String)

    Dim start As DateTime

    Dim elapsed As TimeSpan

    Dim str As String = ""

    start = DateTime.Now

    For i As Integer = 0 To oneBillionInteger

    If (String.IsNullOrEmpty(str)) Then

    End If

    Next i

    elapsed = DateTime.Now – start

    Console.WriteLine("  If (String.IsNullOrEmpty("""")) :" + vbTab + (elapsed.TotalMilliseconds / oneBillionDouble).ToString("f15") + " milliseconds")

    End Sub

    Private Sub StringEqualsNothing(ByVal input As String)

    Dim start As DateTime

    Dim elapsed As TimeSpan

    Dim str As String = ""

    start = DateTime.Now

    For i As Integer = 0 To oneBillionInteger

    If (str = Nothing) Then

    End If

    Next i

    elapsed = DateTime.Now – start

    Console.WriteLine("  If ("""" = Nothing) :" + vbTab + vbTab + vbTab + (elapsed.TotalMilliseconds / oneBillionDouble).ToString("f15") + " milliseconds")

    End Sub

    Private Sub StringIsNothing(ByVal input As String)

    Dim start As DateTime

    Dim elapsed As TimeSpan

    Dim str As String = ""

    start = DateTime.Now

    For i As Integer = 0 To oneBillionInteger

    If (str Is Nothing) Then

    End If

    Next i

    elapsed = DateTime.Now – start

    Console.WriteLine("  If ("""" Is Nothing) :" + vbTab + vbTab + vbTab + (elapsed.TotalMilliseconds / oneBillionDouble).ToString("f15") + " milliseconds")

    End Sub

    End Module

    [/code]

  5. medhedi says:

    you should call duration.TotalMilliseconds instead of duration.Milliseconds, it returns wrong result!!!

    so the optimal comparison method is ordinal

  6. Bhavesh says:

    Your test are for long strings.  I am doing some heavy comparision with short strings and they are numbers (as string). So I will try with the OrdinalIgnoreCase.

    Do you have any comments about performance of string comparision with short strings ?

  7. mamu says:

    Are the results still valid for .NET 4.0?

Skip to main content