为啥要使用 SqlDataReader 的 GetOrdinal() 方法

Posted

技术标签:

【中文标题】为啥要使用 SqlDataReader 的 GetOrdinal() 方法【英文标题】:Why use the GetOrdinal() Method of the SqlDataReader为什么要使用 SqlDataReader 的 GetOrdinal() 方法 【发布时间】:2010-11-07 22:32:54 【问题描述】:

使用这种语法从 SqlDataReader 读取值有什么区别:

Dim reader As SqlClient.SqlDataReader
reader("value").ToString()

Dim reader As SqlClient.SqlDataReader
reader.GetString(reader.GetOrdinal("value"))

【问题讨论】:

【参考方案1】:

我认为使用 GetOrdinal() 的原因是您可以缓存结果并多次重复使用以提高性能。

例如

Dim reader As SqlClient.SqlDataReader
int valueOrdinal = reader.GetOrdinal("value");
while ( ... )

    var value = reader.GetString(valueOrdinal);

【讨论】:

是否有人知道在行循环中使用 GetOrdinal(..) 与从数据库中检索实际数据相比对性能的影响? 我对 Web API 服务进行了性能测试,该服务从 DB 存储过程中读取大约 30-40 条记录(带有多个结果集)并返回大约 8K 大小的 Json。在这个测试中,我将所有 GetOrdinal() 替换为静态 int 常量,结果我获得了 2% 的性能提升……那么创建这种列名缓存是否值得努力? - 我想在大多数情况下不是。在实际场景中从 DB 读取数据并将数据序列化到 Json 会更多地影响性能,所以我认为当您已经优化了其他所有内容时,序数的缓存将是最后要做的事情...... 我可能读错了,但我相信使用 GetOrdinal 也会解析一行而不依赖于每个项目的索引,因为结果可能并不总是按照人们的预期进行索引。使用 GetOrdinal 允许访问读取器的列值,而无需确切知道值的索引位置在哪里。【参考方案2】:

GetOrdinal 首先执行区分大小写的查找。如果失败,则进行第二次不区分大小写的搜索。 GetOrdinal 对假名宽度不敏感。因为基于序数的查找比命名查找更有效,所以在循环中调用GetOrdinal 效率低下。通过调用GetOrdinal 一次并将结果分配给一个整数变量以在循环中使用来节省时间。

来源:http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.getordinal.aspx

【讨论】:

逐字复制并粘贴自msdn.microsoft.com/en-us/library/… ;-) 为什么不直接链接到整篇文章呢?他的评论缺少很多内容。 通常你不会简单地链接到整篇文章,因为它可能不会永远可用,它也有很多需要阅读的内容。您引用相关部分并链接到它。【参考方案3】:

我只想补充一点,您期望有多少记录的上下文起着重要作用,因为如果您返回单行,那么这两者之间的性能差异不会很大。但是,如果您要遍历许多行,那么使用类型访问器会更好地提高性能,因为它已经过优化。因此,在这种情况下,如果您需要通过使用列名来获得最佳性能,请调用 GetOrdinal 一次,将其放入变量中,然后在循环中使用类型访问器和列序号。这将产生最佳性能。

如果您对性能差异感到好奇,请查看my blog post

【讨论】:

【参考方案4】:

您的里程可能会有所不同,但是...

您获取的行越多,您将看到更多的性能改进。我喜欢在我的 SELECT 语句中使用列别名,比如

select
    physical_column_name as "MyFieldName"

并且已经写了一个方法,应该是不言自明的,

public Dictionary<String, Int32> GetOrdinalsByName(DbDataReader reader)

那么,我的作业看起来像

    public void BindRow(DbDataReader dr)
    
        TerminationDate = dr.GetDateTime(_columnOrdinals["TerminationDate"]);

字典执行接近 O(1);因此,这是性能和可维护性之间的合理权衡。

【讨论】:

以上是关于为啥要使用 SqlDataReader 的 GetOrdinal() 方法的主要内容,如果未能解决你的问题,请参考以下文章

为啥 SqlDataReader 到 DataTable 只有在我使用单独的字段时才有效?

使用表达式目录树实现SqlDataReader到实体的映射

处理SqlConnection、SqlDataReader、SqlCommand 时要捕获哪些异常?

如何在SqlDataReader中使用Generic

c# IDataReader SqlDataReader 区别

是否可以仅使用 SqlConnection SqlCommand 和 SqlDataReader 来执行数据访问层