這篇文章的產生其實滿奇妙的,由於目前在前端維護MVC後台,理應碰不到ADO.NET層,偏偏資料連接層的速度又奇曼無比,甚至還會發出錯誤訊息。
在資料取得慢的情況下,所有後台的UI都極為緩慢,多數時候充當第一線砲灰。
在最近終於加入了幾位夥伴,於是協助後端同仁優化這段程式碼的念頭就產生了。
這篇文章會比較DataTable.Load、DataAdapter.Fill、DataReader三者的差異,一起來看看吧。
DataAdapter.Fill、DataReader、DataTable.Load三者差在哪裡呢?
DataAdapter是填入DataSet,將資料常駐在記憶體的一種方式
DataReader提供未緩衝處理的資料流的資料,讓程序邏輯有效地循序處理來自資料來源的結果。 DataReader擷取大量資料,因為資料不會快取記憶體時,是不錯的選擇。
DataTable.Load傳入IDataReader,並在內部執行DbDataAdapter.Fill,而DbDataAdapter則是繼承自DataAdapter
這樣看起來應比較的只有前二個,不過看在DataTable.Load處於一個滿奇妙的位置,於是也將DataTable.Load列入比較,畢竟要調整的是效能嘛XD
如果要了解ADO.NET,以下這二篇滿推薦的
裡面就有講到關於效能的差異了
找到方向後就是寫程式碼實測啦!
首先先列出五個可能的方向
1.DataTable.Load(IDataReader)
IDataReader reader = cmd.ExecuteReader();
using (DataSet ds = new DataSet())
{
do
{
var table = new System.Data.DataTable();
table.Load(reader);
ds.Tables.Add(table);
} while (!reader.IsClosed);
}
這裡的reader 沒用using包起來是測試時候懶惰,記得要加上啊!!
2.DataTable.Load(IDataReader) - IDataReader使用CommandBehavior.SequentialAccess
CommandBehavior behavior = CommandBehavior.SequentialAccess;
IDataReader reader = cmd.ExecuteReader(behavior);
using (DataSet ds = new DataSet())
{
do
{
var table = new System.Data.DataTable();
table.Load(reader);
ds.Tables.Add(table);
} while (!reader.IsClosed);
}
3.IDataReader
IDataReader reader = cmd.ExecuteReader();
using (DataSet ds = new DataSet())
{
do
{
DataTable dtSchema = reader.GetSchemaTable();
DataTable dt = new DataTable();
if (dtSchema != null)
{
foreach (DataRow drow in dtSchema.Rows)
{
string columnName = System.Convert.ToString(drow["ColumnName"]);
DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
dt.Columns.Add(column);
}
}
while (reader.Read())
{
DataRow dataRow = dt.NewRow();
for (int i = 0; i <= reader.FieldCount - 1; i++)
{
dataRow[i] = reader[i];
}
dt.Rows.Add(dataRow);
}
ds.Tables.Add(dt);
} while (reader.NextResult());
}
4.IDataReader - 使用CommandBehavior.SequentialAccess
IDataReader reader = cmd.ExecuteReader(behavior);
using (DataSet ds = new DataSet())
{
do
{
DataTable dtSchema = reader.GetSchemaTable();
DataTable dt = new DataTable();
if (dtSchema != null)
{
foreach (DataRow drow in dtSchema.Rows)
{
string columnName = System.Convert.ToString(drow["ColumnName"]);
DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
dt.Columns.Add(column);
}
}
while (reader.Read())
{
DataRow dataRow = dt.NewRow();
for (int i = 0; i <= reader.FieldCount - 1; i++)
{
dataRow[i] = reader[i];
}
dt.Rows.Add(dataRow);
}
ds.Tables.Add(dt);
} while (reader.NextResult());
reader.Close();
}
5.DataAdapter.Fill
using (SqlDataAdapter sa = new SqlDataAdapter(cmd))
{
using (DataSet ds = new DataSet())
{
sa.Fill(ds);
}
}
測試的程式碼可以參考我的github
測試的結果為DB回傳資料數十筆,每個測試五十次取平均值,只比較SQL執行結束,資料轉換到程式端的時間
測出來的排名為
1.IDataReader - 使用CommandBehavior.SequentialAccess
2.IDataReader
3.DataTable.Load(IDataReader) - IDataReader使用CommandBehavior.SequentialAccess
4.DataAdapter.Fill
5.DataTable.Load(IDataReader)
第一名與第四名的結果差了八十倍以上,以上給各位做為參考。
另外有趣的一點是
DataAdapter.Fill取得的DataSet,第一個Table名稱叫做Table,第二個Table名稱叫做Table1
DataTable.Load取得的DataSet,第一個Table名稱叫做Table1,第二個Table名稱叫做Table2
在程式的轉換過程中因此這個踩了一些小雷XD
歡迎您的加入,讓這個社群更加美好!