【问题标题】:SqlDataReader Performance List<string[]> or List<object[]>SqlDataReader 性能 List<string[]> 或 List<object[]>
【发布时间】:2011-11-06 21:34:31
【问题描述】:

我一直在尝试尽可能快地从 SQL 服务器读取数据的方法,并且发现了一个有趣的发现。如果我将数据读入List&lt;object[]&gt; 而不是List&lt;string[]&gt;,性能会提高一倍以上。

我怀疑这是因为不必在字段上调用ToString() 方法,但我一直认为使用对象会对性能产生负面影响。

是否有任何理由不使用对象数组列表而不是字符串数组?

编辑:我刚刚想到的是这些数据的存储大小。将数据存储在对象数组中会比字符串占用更多空间吗?

这是我的测试代码:

private void executeSqlObject()
    {
        List<object[]> list = new List<object[]>();

        using (SqlConnection cnn = new SqlConnection(_cnnString))
        {
            cnn.Open();
            SqlCommand cmd = new SqlCommand("select * from test_table", cnn);

            SqlDataReader reader = cmd.ExecuteReader();

            int fieldCount = reader.FieldCount;

            while (reader.Read())
            {
                object[] row = new object[fieldCount];

                for (int i = 0; i < fieldCount; i++)
                {
                    row[i] = reader[i];
                }
                list.Add(row);
            }
        }
    }

    private void executeSqlString()
    {
        List<string[]> list = new List<string[]>();

        using (SqlConnection cnn = new SqlConnection(_cnnString))
        {
            cnn.Open();
            SqlCommand cmd = new SqlCommand("select * from test_table", cnn);

            SqlDataReader reader = cmd.ExecuteReader();

            int fieldCount = reader.FieldCount;

            while (reader.Read())
            {
                string[] row = new string[fieldCount];

                for (int i = 0; i < fieldCount; i++)
                {
                    row[i] = reader[i].ToString();
                }
                list.Add(row);
            }
        }
    }

    private void runTests()
    {
        Stopwatch watch = new Stopwatch();
        for (int i = 0; i < 10; i++)
        {
            watch.Start();
            executeSqlObject();
            Debug.WriteLine("Object Time: " + watch.ElapsedMilliseconds.ToString());
            watch.Reset();
        }
        for (int i = 0; i < 10; i++)
        {
            watch.Start();
            executeSqlString();
            Debug.WriteLine("String Time: " + watch.ElapsedMilliseconds.ToString());
            watch.Reset();
        }
    }

结果:

Object Time: 879
Object Time: 812
Object Time: 825
Object Time: 882
Object Time: 880
Object Time: 905
Object Time: 815
Object Time: 799
Object Time: 823
Object Time: 817
Average: 844

String Time: 1819
String Time: 1790
String Time: 1787
String Time: 1856
String Time: 1795
String Time: 1731
String Time: 1792
String Time: 1799
String Time: 1762
String Time: 1869
Average: 1800

【问题讨论】:

  • 无法与结果争论。您还应该将您的阅读器(和命令)也包含在 using 语句中,因为它们会泄漏内存。
  • 测试肯定有问题...相比从数据库读取数据,使得字符串类型检查应该可以忽略不计。
  • 出于好奇,如果您只是将 reader 值转换为字符串 (row[i] = (string)reader[i];) 而不是在其上调用 ToString(),或者使用内置的 @987654328,这有什么不同吗? @方法来检索值(row[i] = reader.GetString(i);)? (A假设所有列值都是字符串。)
  • @Guffa 并没有说明这只是类型检查;这很可能是从其他数据类型到格式化形式的转换。毫无疑问,这会增加工作量。
  • @Guaffa - 正如 Marc 所说,正是从非字符串类型的转换导致了问题 - 当我使用 reader[i] 作为字符串时,我注意到与 object[] 测试的性能相似。

标签: c# performance sqldatareader


【解决方案1】:

object 仅在您造成额外装箱时才会增加开销。即便如此,这种影响也相当小。在您的情况下,reader[i] 总是 返回 object。您已经将它作为object 获得,无论它是对字符串的引用还是对int 等的引用。当然 调用.ToString() 会增加开销;在大多数情况下(int、DateTime 等),这涉及格式化代码一个(或多个)额外字符串的分配。通过更改为string,您将更改数据(更糟糕的是,IMO - 例如,您不能再对日期进行正确排序)并增加开销。这里的边缘情况是所有列实际上都已经是字符串 - 在这种情况下,您只需添加一些虚拟方法调用(但没有额外的实际工作)。

有关信息,如果您追求原始性能,我强烈建议您查看微型 ORM,例如 dapper。它们经过大量优化,但避免了“完整” ORM 的重量。例如,在 dapper 中:

var myData = connection.Query<TypedObject>("select * from test_table").ToList();

我希望,在为您提供强类型对象数据的同时,性能非常相似。

【讨论】:

  • 马克,感谢您提供的信息。参考微 ORM 解决方案,此解决方案是否不需要我在执行查询之前知道我正在检索的数据集?我需要这个应用程序不知道它正在检索的数据
  • @ChandlerPelhams 从问题中不清楚;p 假设您不能通过泛型传递 T (在大多数应用程序中,调用者的 some 部分知道数据是什么样子的),那么确实更通用的东西,例如object[],或者正如“lowds”所说的DataTable,可能更合适。
【解决方案2】:

是否有任何理由不使用对象数组列表而不是字符串数组?

这将取决于您在将检索到的值放入数组后想要对它们做什么,如果您乐于将每个值视为一个对象,那么拥有一个对象列表就可以了,但是如果您想将它们视为字符串,然后在某些时候您将不得不将对象转换/转换回字符串,因此您将在某处产生成本。

正如 Cory 所说,如果您从 SqlDataReader 读取值作为字符串,则应该使用 GetString(int) 方法进行测试,而不是对该值调用 ToString(),并将其用作基准。

或者,您可以将值读取到 DataSet 中,而不是使用数组,这样以后可能会更容易使用。

归根结底,什么是最好的很大程度上取决于您从数据库中检索结果后如何使用它们。

【讨论】:

  • 大声笑,DataSet 与数组列表的可用性...认为这是另一个 SO 问题的主题 :)
  • 在给定的情况下,似乎(cmets)代码可能不知道布局,在这种情况下我必须注意DataTable可能确实是合适的。
猜你喜欢
  • 2018-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
相关资源
最近更新 更多