Microsoft (and many developers) claim that the SqlDataReader.GetOrdinal method improves the performance of retrieving values from a DataReader versus using named lookups ie. reader["ColumnName"]. The question is what is the true performance difference if dealing with small, paged record sets? Is it worth the extra overhead of finding and referencing ordinal indexes throughout the code?
- 
                    Some benchmark: http://blog.maskalik.com/ado-net/data-reader-performance-optimizations/ – nawfal Jul 31 '15 at 14:29
 
4 Answers
Microsoft recommends not calling GetOrdinal within a loop.
That would include indirect calls with the string indexer.
You can use GetOrdinal at the top of your loop put the ordinals in an array and have the indexes in the array be const or have an enum for them (no GetOrdinal at all) or use GetOrdinal into individual variables with descriptive names.
Only if your sets are small would I really consider this to be premature optimization.
- 88,164
 - 40
 - 182
 - 265
 
Any difference will be more than outweighed by maintenance overhead.
If you have that much data that it makes a noticeable difference, I'd suggest you have too much data in your client code. Or this is when you consider use ordinals rather than names
- 422,506
 - 82
 - 585
 - 676
 
Yes and no.
If you're dealing with a massive amount of data then you'd certainly benefit from using the ordinals rather than the column names.
Otherwise, keep it simple, readable, and somewhat safer - and stick with the column names.
Optimize only when you need to.
- 24,780
 - 5
 - 50
 - 61
 
- 
                    1"readable, and somewhat safer - and stick with the column names" I would say that is what an ordinal provides. You can give your ordinal a nice name `int ordinalUserName = reader.GetOrdinal("user_name")` so it is also readable. It could also be considered more readable and safer if you declare all of your ordinals in one place rather than having column names scattered inside some logic. – row1 Mar 21 '14 at 05:06
 
I created a wrapper for SqlDataReader that stores orindals in a dictionary with the column name as the key.
It gives me ordinal performance gains while keeping the code more readable and less likely to break if someone changes the column order returned from stored procedures.
Friend Class DataReader
Implements IDisposable
Private _reader As SqlDataReader
Private _oridinals As Dictionary(Of String, Integer)
Private Shared _stringComparer As StringComparer = StringComparer.OrdinalIgnoreCase 'Case in-sensitive
Public Sub New(reader As SqlDataReader)
    Me._reader = reader
    Me.SetOrdinals()
End Sub
Private Sub SetOrdinals()
    Me._oridinals = New Dictionary(Of String, Integer)(_stringComparer)
    For i As Integer = 0 To Me._reader.FieldCount - 1
        Me._oridinals.Add(Me._reader.GetName(i), i)
    Next
End Sub
Public Function Read() As Boolean
    Return Me._reader.Read()
End Function
Public Function NextResult() As Boolean
    Dim value = Me._reader.NextResult()
    If value Then
        Me.SetOrdinals()
    End If
    Return value
End Function
Default Public ReadOnly Property Item(name As String) As Object
    Get
        Return Me._reader(Me.GetOrdinal(name))
    End Get
End Property
Public Function GetOrdinal(name As String) As Integer
    Return Me._oridinals.Item(name)
End Function
Public Function GetInteger(name As String) As Integer
    Return Me._reader.GetInt32(Me.GetOrdinal(name))
End Function
Public Function GetString(ordinal As Integer) As String
    Return Me._reader.GetString(ordinal)
End Function
Public Function GetString(name As String) As String
    Return Me._reader.GetString(Me.GetOrdinal(name))
End Function
Public Function GetDate(name As String) As Date
    Return Me._reader.GetDateTime(Me.GetOrdinal(name))
End Function
Public Function GetDateNullable(name As String) As Nullable(Of Date)
    Dim o = Me._reader.GetValue(Me.GetOrdinal(name))
    If o Is System.DBNull.Value Then
        Return Nothing
    Else
        Return CDate(o)
    End If
End Function
Public Function GetDecimal(name As String) As Decimal
    Return Me._reader.GetDecimal(Me.GetOrdinal(name))
End Function
Public Function GetBoolean(name As String) As Boolean
    Return Me._reader.GetBoolean(Me.GetOrdinal(name))
End Function
Public Function GetByteArray(name As String) As Byte()
    Return CType(Me._reader.GetValue(Me.GetOrdinal(name)), Byte())
End Function
Public Function GetBooleanFromYesNo(name As String) As Boolean
    Return Me._reader.GetString(Me.GetOrdinal(name)) = "Y"
End Function
'Disposable Code
End Class
- 19
 - 2
 
- 
                    1Isn’t SqlDataReader going to already have a Dictionary as part of its GetOrdinal() implementation? Did you actually measure any performance improvements over Item[string]? – binki Sep 17 '13 at 17:24