C# SqlDataReader性能列表<;字符串[]>;或列表<;对象[]>;

C# SqlDataReader性能列表<;字符串[]>;或列表<;对象[]>;,c#,performance,sqldatareader,C#,Performance,Sqldatareader,我一直在尝试尽快从SQL server读取数据的方法,我发现了一个有趣的发现。如果我将数据读入列表而不是列表,性能会提高一倍以上 我怀疑这是因为不必对字段调用ToString()方法,但我一直认为使用对象会对性能产生负面影响 是否有任何理由不使用对象数组列表而不是字符串数组 编辑:我的一个想法是这个数据的存储大小。将数据存储在对象数组中会比作为字符串占用更多的空间吗 以下是我的测试代码: private void executeSqlObject() { List<

我一直在尝试尽快从SQL server读取数据的方法,我发现了一个有趣的发现。如果我将数据读入
列表
而不是
列表
,性能会提高一倍以上

我怀疑这是因为不必对字段调用
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();
        }
    }

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

关于信息,如果您想要获得原始性能,我完全建议您查看micro-ORMs,例如dapper。它们经过了大量优化,但避免了“完整”ORM的重量。例如,在简洁中:

var myData = connection.Query<TypedObject>("select * from test_table").ToList();
var myData=connection.Query(“从测试表中选择*).ToList();
我希望,在提供强类型对象数据时,性能会非常相似

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

这将取决于在将检索到的值放入数组后,您希望对其执行什么操作,如果您愿意将每个值视为一个对象,则可以拥有一个对象列表,但是如果你想把它们当作字符串,那么在某个时候你必须将对象转换/转换回字符串,这样你就要在某个地方付出代价

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

或者,您可以将值读入数据集中,而不是使用数组,这样以后可能更容易使用


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

不能对结果提出异议。你也应该用语句来包装你的读卡器(还有命令),因为这些语句可能会泄漏内存。。。与从数据库读取数据相比,进行字符串类型检查应该可以忽略不计。出于好奇,如果您只是将读取器值转换为字符串(
row[i]=(string)reader[i];
),而不是对其调用
ToString()
,或者使用内置的
SqlDataReader.GetString()
检索值的方法(
行[i]=reader.GetString(i);
)?(所有列值都是字符串。)@Guffa没有说明这只是一个类型检查;这很可能是从其他数据类型到格式化格式的转换。毫无疑问,这会增加工作量。@Guaffa-正如Marc所说,正是从非字符串类型的转换导致了问题-当我将reader[I]用作string.lol时,我注意到与object[]测试类似的性能,DataSet的可用性与数组列表。。。我认为这是另一个问题的主题:)在给定的情况下,代码可能不知道布局,在这种情况下,我必须注意DataTable可能确实是合适的。Marc,谢谢你提供的好信息。关于micro ORM解决方案,这个解决方案不要求我在执行查询之前知道正在检索的数据集吗?我需要这个应用程序是不可知的数据,它是retrieving@ChandlerPelhams这个问题并不清楚;p假设您不能通过泛型传递
t
(在大多数应用程序中,调用方的某些部分知道数据是什么样子),那么实际上更通用的东西,例如
object[]
,或者,如“lowds”所述,
DataTable
,可能更合适。
var myData = connection.Query<TypedObject>("select * from test_table").ToList();