在以下代码中,command是已经设置的DbCommand:
using( var dataReader = command.ExecuteReader() /*The actual execution of the query takes relatively little time.*/ ) {
while( dataReader.Read() ) {
// These are what take all of the time. Replacing them all with reader.GetValues( myArray ) has no impact.
val0 = dataReader.GetValue( 0 );
val1 = dataReader.GetValue( 1 );
val2 = dataReader.GetValue( 2 );
}
}
我目前正在处理的查询的大部分时间都用于GetValue调用。它是否为每个GetValue调用进行数据库往返?看起来似乎是这样,这看起来非常低效。正如代码所指出的那样,尝试使用GetValues()一次性完成它并没有什么不同。有没有办法一次性获得整行?更好的是,有没有办法一次性获得整个结果集?
感谢。
答案 0 :(得分:33)
我用各种方法做了一些基准测试:
public DataTable Read1(string query)
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.Connection.Open();
var table = new DataTable();
using (var r = cmd.ExecuteReader())
table.Load(r);
return table;
}
}
public DataTable Read2<S>(string query) where S : IDbDataAdapter, IDisposable, new()
{
using (var da = new S())
{
using (da.SelectCommand = conn.CreateCommand())
{
da.SelectCommand.CommandText = query;
DataSet ds = new DataSet();
da.Fill(ds);
return ds.Tables[0];
}
}
}
public IEnumerable<S> Read3<S>(string query, Func<IDataRecord, S> selector)
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.Connection.Open();
using (var r = cmd.ExecuteReader())
while (r.Read())
yield return selector(r);
}
}
public S[] Read4<S>(string query, Func<IDataRecord, S> selector)
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.Connection.Open();
using (var r = cmd.ExecuteReader())
return ((DbDataReader)r).Cast<IDataRecord>().Select(selector).ToArray();
}
}
public List<S> Read5<S>(string query, Func<IDataRecord, S> selector)
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.Connection.Open();
using (var r = cmd.ExecuteReader())
{
var items = new List<S>();
while (r.Read())
items.Add(selector(r));
return items;
}
}
}
1和2返回DataTable
,而其余的强类型结果集,所以它完全不是苹果到苹果,但我在相应的时间内。
只是要点:
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 100; i++)
{
Read1(query); // ~8900 - 9200ms
Read1(query).Rows.Cast<DataRow>().Select(selector).ToArray(); // ~9000 - 9400ms
Read2<MySqlDataAdapter>(query); // ~1750 - 2000ms
Read2<MySqlDataAdapter>(query).Rows.Cast<DataRow>().Select(selector).ToArray(); // ~1850 - 2000ms
Read3(query, selector).ToArray(); // ~1550 - 1750ms
Read4(query, selector); // ~1550 - 1700ms
Read5(query, selector); // ~1550 - 1650ms
}
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());
查询返回了大约1200行和5个字段(运行100次)。除了Read1
之外,所有表现都很好。我更喜欢Read3
懒惰返回数据,如枚举。如果您只需要枚举它,这对内存很有用。要在内存中获得该集合的副本,您最好随时使用Read4
或Read5
。
答案 1 :(得分:5)
using (connection)
{
SqlCommand command = new SqlCommand(
"SELECT CategoryID, CategoryName FROM dbo.Categories;" +
"SELECT EmployeeID, LastName FROM dbo.Employees",
connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.HasRows)
{
Console.WriteLine("\t{0}\t{1}", reader.GetName(0),
reader.GetName(1));
while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
reader.NextResult();
}
}
答案 2 :(得分:4)
我会使用类似dapper-dot-net的东西将其加载到基本类型模型中;这是一个微型ORM,因此您可以获得元编程(有效预生成IL等)的好处 - 而无需EF或DataTable之类的开销。
答案 3 :(得分:1)
您可以使用DbDataAdapter
获取所有结果并将其存储在DataTable
中。
答案 4 :(得分:1)
Dim adapter As New Data.SqlClient.SqlDataAdapter(sqlCommand)
Dim DT As New DataTable
adapter.Fill(DT)
答案 5 :(得分:-1)
使用无类型数据集。据我所知,这是最快的。