【问题标题】:C# - SQLDataReader by Index vs. SQLDataReader.GetOrdinal(ColumnName)C# - 按索引的 SQLDataReader 与 SQLDataReader.GetOrdinal(ColumnName)
【发布时间】:2020-03-16 06:56:07
【问题描述】:

一种被认为是更好的标准吗?一个比另一个快吗?或者,只是主要是偏好? GetOrdinal 很好,因为您可以自己调用列名,而不必担心计算 SQL 中字段的索引,但我想知道使用其中一个是否有好处。

按索引阅读:

            while (reader.Read())
            { 
                Column1 = reader.GetValue(0).ToString().Trim();
                Column2 = reader.GetValue(1).ToString().Trim();
            }

Reader.GetOrdinal:

           while (reader.Read())
           {
               data.Column1 = reader.GetValue(reader.GetOrdinal("COLUMN1")).ToString();
               data.Column2 = reader.GetValue(reader.GetOrdinal("COLUMN2")).ToString();
               data.Column3 = reader.GetDateTime(reader.GetOrdinal("COLUMN3"));
           }

【问题讨论】:

  • 按索引读取更快。 GetOrdinal 需要比较的字符串不如按索引访问数组元素那么快。
  • 我认为按索引阅读更快,但我有一些开发人员坚持认为 GetOrdinal 是“更好的标准”。我目前的工作是关于速度,所以我们的领导希望我们按索引阅读是有道理的。由于某种原因,我的上一份工作坚持使用 GetOrdinal 更好。很高兴知道!

标签: c# sql asp.net ado.net sqldatareader


【解决方案1】:

我总是使用返回字典的函数,其中列名作为键,索引作为值,就像那个:

public IDictionary<string, int> GetColumnNames(ref SqlDataReader reader) {
    IDictionary<string, int> dict = new Dictionary<string, int>();
    if (reader == null)
        return dict;
    int columns = reader.FieldCount;

    for (int i = 0; i < columns; i++) {
        dict[reader.GetName(i)] = i;
    }

    return dict;
}

那么您可以随时创建新对象并进行调用:

var cols = GetColumnNames(ref r);
while (r.Read())
    var value = r.GetInt32(cols["SOME_COLUMN"]);

我真的不知道它是否更快,但对我有用。 此外,与定义的常量列名一起使用也很好。

【讨论】:

  • 我从没见过这样使用它,但非常有趣。感谢分享。
  • YW。它仍然比仅仅调用索引要慢,但是你可以将列存储一次,这对数十或数百行是有益的。
【解决方案2】:

reader.GetOrdinal(string) 将获取列序号,给定列的名称

我们可以从SqlDataReader 中看到GetOrdinal 源代码,它将返回来自_fieldNameLookup.GetOrdinal 的索引(_fieldNameLookup 字段是FieldNameLookup 类)

_fieldNames是一个哈希表存储索引,区分大小写匹配

override public int GetOrdinal(string name) {
    SqlStatistics statistics = null;
    try {
        statistics = SqlStatistics.StartTimer(Statistics);
        if (null == _fieldNameLookup) {
            CheckMetaDataIsReady();
            _fieldNameLookup = new FieldNameLookup(this, _defaultLCID);
        }
        return _fieldNameLookup.GetOrdinal(name); // MDAC 71470
    }
    finally {
        SqlStatistics.StopTimer(statistics);
    }
}

我们可以从FieldNameLookup类中看到源代码GetOrdinal方法。

public int GetOrdinal(string fieldName) { // V1.2.3300
    if (null == fieldName) {
        throw ADP.ArgumentNull("fieldName");
    }
    int index = IndexOf(fieldName);
    if (-1 == index) {
        throw ADP.IndexOutOfRange(fieldName);
    }
    return index;
}

public int IndexOf(string fieldName) { // V1.2.3300
    if (null == _fieldNameLookup) {
        GenerateLookup();
    }
    int index;
    object value = _fieldNameLookup[fieldName];
    if (null != value) {
        // via case sensitive search, first match with lowest ordinal matches
        index = (int) value;
    }
    else {
        // via case insensitive search, first match with lowest ordinal matches
        index = LinearIndexOf(fieldName, CompareOptions.IgnoreCase);
        if (-1 == index) {
            // do the slow search now (kana, width insensitive comparison)
            index = LinearIndexOf(fieldName, ADP.compareOptions);
        }
    }
    return index;
}

一个比另一个快吗?

如果您已经知道列存在索引号reader.GetValue(0) 会比reader.GetValue(reader.GetOrdinal("COLUMN1")) 更快,因为它不会导致资源从reader.GetOrdinal 方法获取列索引。

一种被认为是更好的标准吗?

没有比较标准,因为reader.GetValue(0) 和reader.GetValue(reader.GetOrdinal("COLUMN1")) 正在做同样的事情,和之前的答案一样。

reader.GetValue(reader.GetOrdinal("COLUMN1")) 比reader.GetValue(0) 更好阅读,因为列名会更好地知道而不是索引。

【讨论】:

  • 感谢您的详细回答!现在,为什么我们在我目前的工作(为了速度)中按索引阅读,但在我的上一份工作中使用 GetOrdinal(标准/不关心速度)是有道理的。当您在大查询中添加新字段并且必须重做所有索引时,这很糟糕,但如果让您的执行更快,这是值得的。
  • @AndrewReese 没问题很高兴帮助
猜你喜欢
  • 1970-01-01
  • 2013-07-22
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
相关资源
最近更新 更多