DataReader基于序号的查找与命名查找

5

微软(以及许多开发人员)声称 SqlDataReader.GetOrdinal 方法比使用命名查找,例如 reader["ColumnName"],提高了从 DataReader 检索值的性能。问题是在处理小型分页记录集时,真正的性能差异是什么?是否值得在代码中寻找和引用序数索引所带来的额外开销?


一些基准测试:http://blog.maskalik.com/ado-net/data-reader-performance-optimizations/ - nawfal
4个回答

6

微软建议不要在循环中调用GetOrdinal方法。

这包括使用字符串索引器进行的间接调用。

您可以在循环顶部使用GetOrdinal将序数放入数组中,并使数组中的索引为const或具有枚举(根本不需要GetOrdinal),或者使用GetOrdinal转换为具有描述性名称的单个变量。

只有当数据集很小的时候,我才会真正考虑这种过早的优化。

显然会有3%的惩罚。


5
任何差异都将被维护开销所抵消。
如果您有大量数据,以至于会产生明显的差异,我建议您在客户端代码中拥有过多的数据。或者这是当您考虑使用序数而不是名称时的情况。

2

是和不是。

如果你正在处理大量数据,使用序数而不是列名肯定会对你有所帮助。

否则,保持简单、可读和相对安全 - 使用列名即可。

只有在需要时才进行优化。


1
我认为这就是序数提供的功能——可读性更强,相对更安全,并且坚持使用列名。你可以给你的序数取一个好听的名字,例如 int ordinalUserName = reader.GetOrdinal("user_name"),这样也更容易阅读。如果你在一个地方声明所有的序数而不是将列名散布在某些逻辑中,那么它也可以被认为是更易读和更安全的。 - row1

-1
我为SqlDataReader创建了一个包装器,将原始数据存储在字典中,以列名为键。
这使得代码更易读,并且在保持性能的同时,不太可能因为有人更改从存储过程返回的列顺序而导致代码出错。
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

1
SqlDataReader的GetOrdinal()实现不是已经包含了Dictionary吗?你是否真的测量过与Item[string]相比的性能改进? - binki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接