我一直在尝试尽快从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
object
仅在引起额外的装箱时才会增加开销。即便如此,这种影响也相当小。在您的例子中,reader[i]
总是返回object
。您已经有了object
,无论它是对字符串还是int的引用,等等。course调用.ToString()
增加开销;在大多数情况下(int, DateTime等),这涉及到格式化代码和分配一个(或多个)额外字符串。通过更改为string
,您将更改数据(更糟糕的是,在我看来-例如,您不能再对日期进行正确的排序,例如)并增加开销。这里的极端情况是,如果所有列实际上已经是字符串—在这种情况下,您只需添加一些虚拟方法调用(但不需要额外的实际工作)。
对于信息,如果您追求原始性能,我强烈建议查看微orm,如dapper。它们经过了大量优化,但避免了"完整"orm的权重。例如,在dapper:
var myData = connection.Query<TypedObject>("select * from test_table").ToList();
我希望在提供强类型对象数据时的性能与之相当。
是否有任何理由不使用对象数组列表而不是字符串数组?
这取决于你想如何处理检索到的值,当你把它们放入数组中,如果你愿意把每个值作为一个对象,那么有一个对象列表是可以的,但如果你想把它们作为字符串,那么在某些时候,你将不得不把对象转换/强制转换回字符串,所以你将在某处产生成本。
正如Cory所提到的,如果您从SqlDataReader中读取作为字符串的值,则应该使用GetString(int)方法进行测试,而不是对值调用ToString(),并将其用作基准。
或者,你可以将值读入数据集,而不是使用数组,这可能证明以后更容易处理。
在一天结束的时候,什么是最好的在很大程度上取决于你想如何使用从数据库中检索结果。