在.Net数据集中,使用列名还是列索引更好?

7

从DataRow中检索值时,使用列名还是列索引更好?

列名更易读且更易维护:

int price = (int)dr["Price"];

尽管我认为列索引只是更快的方式:

int price = (int)dr[3];

如果您决定对数据库进行混淆,使用列名是否会出现问题?

11个回答

13

我通常更注重代码的可读性和易懂性,而非其运行速度。按照字段名称命名变量是一个不错的选择。你可以(也应该)使用字符串常量来表示数据库列名,在需要更改时只需更新一处即可。


我尝试使用名称 - int price = (int)dr["Price"]; 我得到一个错误 - 无法隐式转换类型字符串为整数。我该如何解决?谢谢。 - Steam
@blasto - 如果你的列是字符串,你需要使用 int price = int.Parse(dr["Price"]); - tvanfosson
@tvanfosson "你可以(应该)使用字符串常量",使用ColumnName.Name怎么样?或者有什么缺点吗? - 41686d6564 stands w. Palestine

11

通过列名访问列/行的值更有利于人类阅读和前向兼容性(如果将来有人更改列的顺序或数量)。

通过列索引访问列/行的值更有利于性能。

因此,如果您想在一两个......行中更改某些值,则使用列名是可以的。 但是,如果您想在数千行中更改某些值,则应使用从列名计算出的列索引:

int ndxMyColumn = table.Columns.IndexOf( "MyColumn" );
foreach(DataRow record in table.Rows ) {
    record[ndxMyColumn] = 15;
}

5
完全同意其他人的意见,选择可读性和可维护性而不是速度。然而,我有一个通用方法,需要将命名列传递为参数,所以有意义的是要弄清它们的列索引。
在下面的基准测试中,使用列索引显示出了巨大的改进,因此如果这是代码的瓶颈区域或性能关键部分,那么这可能是值得的。
下面代码的输出是:
使用ColumnIndex:515毫秒
使用ColumnName:1031毫秒
    static void Main(string[] args)
    {            
        DataTable dt = GetDataTable(10000, 500);
        string[] columnNames = GetColumnNames(dt);

        DateTime start = DateTime.Now;
        TestPerformance(dt, columnNames, true);

        TimeSpan ts = DateTime.Now.Subtract(start);
        Console.Write("{0}ms with ColumnIndex\r\n", ts.TotalMilliseconds);

        start = DateTime.Now;
        TestPerformance(dt, columnNames, false);
        ts = DateTime.Now.Subtract(start);
        Console.Write("{0}ms with ColumnName\r\n", ts.TotalMilliseconds);
    }

    private static DataTable GetDataTable(int rows, int columns)
    {
        DataTable dt = new DataTable();

        for (int j = 0; j < columns; j++)
        {
            dt.Columns.Add("Column" + j.ToString(), typeof(Double));
        }

        Random random = new Random(DateTime.Now.Millisecond);
        for (int i = 0; i < rows; i++)
        {
            object[] rowValues = new object[columns];

            for (int j = 0; j < columns; j++)
            {
                rowValues[j] = random.NextDouble();
            }

            dt.Rows.Add(rowValues);
        }

        return dt;
    }

    private static void TestPerformance(DataTable dt, string[] columnNames, bool useIndex)
    {
        object obj;
        DataRow row;

        for (int i =0; i < dt.Rows.Count; i++)
        {
            row = dt.Rows[i];

            for(int j = 0; j < dt.Columns.Count; j++)
            {
                if (useIndex)
                    obj = row[j];
                else
                    obj = row[columnNames[j]];
            }
        }
    }

    private static string[] GetColumnNames(DataTable dt)
    {
        string[] columnNames = new string[dt.Columns.Count];

        for (int j = 0; j < columnNames.Length; j++)
        {
            columnNames[j] = dt.Columns[j].ColumnName;
        }

        return columnNames;
    }

3

我认为列名是最好的选择。这样更容易确定您正在提取什么,并且列顺序由选择语句确定,而选择语句可能会在以后更改。您可能会争论列名也可能会更改,但我认为这种情况发生的可能性要小得多。

编辑:

实际上,如果您非常想使用列索引,可以创建列索引的常量并将常量命名为列的名称。如下:

PRIMARY_KEY_COLUMN_NAME_INDEX = 0

那至少能使其可读。

你应该为字符串也创建一个变量。 - Aaron Fischer
实际上,它们应该是常量而不是变量。我也会在某些情况下质疑这样做的价值,特别是如果数据集只会在一个地方被访问。如果以后发生变化,那么可以进行重构。 - kemiller2002

2

这取决于您的需求。 在我的情况下,我需要对DataSet中的数千行进行强烈的处理,因此速度至关重要,所以我选择编写了一段代码,通过名称缓存列索引。 然后,在循环代码中,我使用了缓存的索引。相比直接使用列名,这样做可以显著提高性能。

当然,您的情况可能会有所不同。我的情况是一个相当牵强和不寻常的例子,但在那种情况下,它表现得相当出色。


2

我的观点是,只有在对代码进行了性能分析并显示其为瓶颈时,才应该切换到索引。我认为这种情况不太可能发生。

命名东西很好,它使我们有限的大脑更容易理解问题和建立联系。这就是为什么我们会被赋予像Fred、Martin、Jamie这样的名字,而不是Human[189333847]、Human[138924342]和Human[239333546]。


1

如果您决定在未来通过更改列名来混淆数据库,您可以在查询中为这些列设置别名以保持索引器代码的功能。我建议按名称进行索引。


1

跟着名字走,你会得到更好的错误信息 :)


1

我选择使用字符串来提高代码的可读性和可维护性。我使用字符串常量来定义列名的值。例如:

public class ExampleDataColumns
{
    public const string ID = "example_id";
    public const string Name = "example_name";
    ....    
}

然后我以后可以这样引用它:

row[ExampleDataColumns.ID]

1

使用列名称为DataRow命名,同样地,RDBMS要求程序员在SQL中指定列索引不会提高速度。但是您可以模仿RDBMS操作的方式,在发出SELECT语句时,在RDBMS引擎内查询在SELECT子句中指定的列的列索引/偏移量,然后再遍历行,这样可以更快地操作。

如果您真的想提高速度,请不要使用const/enum方式(列顺序可能会在数据库或ORM层上更改)。请按照TcKs建议的方式进行操作(在实际循环之前):

int ndxMyColumn = table.Columns.IndexOf( "MyColumn" );
foreach(DataRow record in table.Rows ) {
    record[ndxMyColumn] = 15;
}

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