从DbDataReader读取数据的最快方法是什么?

在以下代码中,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()一次性完成它并没有什么不同。 有没有办法一次性获得整行? 更好的是,有没有办法一次性获得整个结果集?

谢谢。

 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(); } } 

我用各种方法做了一些基准测试:

 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(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 Read3(string query, Func 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(string query, Func selector) { using (var cmd = conn.CreateCommand()) { cmd.CommandText = query; cmd.Connection.Open(); using (var r = cmd.ExecuteReader()) return ((DbDataReader)r).Cast().Select(selector).ToArray(); } } public List Read5(string query, Func selector) { using (var cmd = conn.CreateCommand()) { cmd.CommandText = query; cmd.Connection.Open(); using (var r = cmd.ExecuteReader()) { var items = new List(); 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().Select(selector).ToArray(); // ~9000 - 9400ms Read2(query); // ~1750 - 2000ms Read2(query).Rows.Cast().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之外,所有表现都很好。 我喜欢Read3Read3返回数据,如枚举。 如果您只需枚举它,这对内存很有用。 要在内存中拥有该集合的副本,您最好使用Read5Read5

我会使用dapper-dot-net之类的东西将它加载到基本类型模型中; 这是一个微型ORM,因此您可以获得元编程(有效预生成IL等)的好处 – 而无需EF或DataTable之类的开销。

  Dim adapter As New Data.SqlClient.SqlDataAdapter(sqlCommand) Dim DT As New DataTable adapter.Fill(DT) 

您可以使用DbDataAdapter获取所有结果并将它们存储在DataTable

使用Untyped DataSet。 据我所知,这是最快的。