有意义的是,基于名称的查找可能会比使用多个匹配规则慢一点,而不是整数索引。但是,当我们讨论数据集中平均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
答案 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);
}
}