2011-04-22 184 views
17

在下面的代碼,命令是已經成立了的DbCommand:什麼是從DbDataReader讀取數據的最快方法?

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()一次性完成它並沒有什麼不同。有一種方法可以一次獲得整行數據嗎?更好的是,有沒有辦法一次性得到整個結果集?

謝謝。

回答

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

這並不比我在原始問題中發佈的代碼更快(大致相同),但我認爲這是答案中最快的。至少我們現在知道,我沒有找到更快的方法。 – 2012-04-29 18:46:09

1

您可以使用DbDataAdapter獲取所有結果並將它們存儲在DataTable中。

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

我會使用類似dapper-dot-net將其加載到一個基本類型的模型;這是一個micro-ORM,所以你可以獲得元編程的好處(有效地預先生成IL等),而不需要像EF或DataTable那樣的開銷。

+3

我不認爲這將有助於他關於數據讀者的具體問題。 Dapper本身使用DbDataReader.GetValue。 – 2014-07-22 14:42:16

26

我做了一些與各種方法標杆自己:

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其中列舉延遲返回數據。如果你只需要枚舉它,這對記憶很有用。要在內存中擁有該集合的副本,您最好使用Read4Read5

+1

+1 - 有趣,尤其是'DataTable.Load()'和'IDataAdapter.Fill()'之間的比較。我會認爲數據適配器與直接加載到'DataTable'相同或更慢,但它看起來更快了4-5倍?任何想法爲什麼? – 2013-02-13 19:11:11

+0

@TimMedora不知道,但我確認它與'SQLite連接器'嘗試,併產生了相同的結果,我回答[這裏](http://stackoverflow.com/a/14807940/661933)。儘管如此,它很奇怪。 – nawfal 2013-02-13 19:13:07

+1

@TimMedora:您需要用'.BeginLoadData()'和'.EndLoadData()'環繞'DataTable.Load()'以達到與'DataSet'相同的速度。 – 2014-04-18 14:43:57

0

使用無類型的數據集。就我所知,這是最快的。

相關問題