SqlDataReader性能列表<string []>或List <object []> </object []> </string []>

时间:2011-11-06 21:34:32

标签: c# performance sqldatareader

我一直在尝试尽快从SQL服务器读取数据的方法,我遇到了一个有趣的发现。如果我将数据读入List<object[]>而不是List<string[]>,则性能会提高一倍以上。

我怀疑这是因为不必在字段上调用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

2 个答案:

答案 0 :(得分:8)

如果您导致其他装箱,

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

有关信息,如果您是在原始性能之后,我会完全建议您查看微型ORM,例如dapper。它们经过了大量优化,但避免了“完整”ORM的重量。例如,在小巧玲珑中:

var myData = connection.Query<TypedObject>("select * from test_table").ToList();
我希望,在给你强类型对象数据的同时,它会表现得非常可比。

答案 1 :(得分:1)

  

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

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

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

或者,您可以将值读入DataSet,而不是使用数组,这可能会更容易在之后使用。

当天结束时,最好的方法取决于您在从数据库中检索结果后如何使用结果。