DataReader基于名称的查找 - 实际上发生了什么使得它们比循环中基于序数的查找慢得多?

时间:2013-04-29 19:37:03

标签: .net sql sql-server sqldatareader datareader

有意义的是,基于名称的查找可能会比使用多个匹配规则慢一点,而不是整数索引。但是,当我们讨论数据集中平均10-15 [列]条目的数量时,我很难相信这解释了每行的3%(或我项目的5-7%)相对成本。在前面的陈述中值得澄清的是,我指的是这种“解除引用”发生的列数,而不是数据集中的记录数。上面的这些成本是在这些查找每行发生一次的情况下。所以他们可能会发生很多事情。

idr.GetOrdinal(name) // Name based lookup
idr[name]  // Name-based lookup
idr.GetValue(index) // Ordinal-based lookup

实际上是否需要与数据库进行基于名称的字段查找的额外通信?是什么让他们这么慢?

我还注意到为列名提供以下代码:

List<string> columnList = new List<string>();
for (int i = 0; i < idr.FieldCount; i++)
{
    columnList.Add(idr.GetName(i));
}

return columnList;

比使用GetSchemaTable的同等版本更快 ,我猜这是出于同样的原因。

这个问题的精神源于: Ordinal-Based Lookups vs. Name Based Lookups

2 个答案:

答案 0 :(得分:3)

这是GetOrdinal的{​​{1}}代码,使用ILSpy提取的.NET 4.0。

SqlDataReader

如您所见,没有额外的数据库访问权限。 public override int GetOrdinal(string name) { SqlStatistics statistics = null; int ordinal; try { statistics = SqlStatistics.StartTimer(this.Statistics); if (this._fieldNameLookup == null) { if (this.MetaData == null) { throw SQL.InvalidRead(); } this._fieldNameLookup = new FieldNameLookup(this, this._defaultLCID); } ordinal = this._fieldNameLookup.GetOrdinal(name); } finally { SqlStatistics.StopTimer(statistics); } return ordinal; } 使用FieldNameLookup来存储字段名称,并在第一次调用Hashtable时加载后缓存。因此,GetOrdinal调用将为通过GetOrdinal完成的查找添加非常少量的开销,而FieldNameLookup调用也可能会增加一点开销(尽管可能不多)。

一个好的测试是使用SqlStatistics来存储索引并查找每行Hashtable中每列的索引。如果性能与为每行调用Hashtable相同,那么您可以安全地假设开销在GetOrdinal次调用中。

希望有所帮助。

答案 1 :(得分:1)

你可以lookup the sourcecode for .NET framework objects to see what is happening under-the-hood。从这个例子:

override public  Int32 GetOrdinal (string name) { 

            ValidateOpen("GetOrdinal");
            ValidateReader(); 
            DataColumn dc = currentDataTable.Columns[name];

            if (dc != null) {
                return dc.Ordinal;// WebData 113248 
            }
            else{ 
                throw ExceptionBuilder.ColumnNotInTheTable(name, currentDataTable.TableName); 
            }
        }