ADO.NET資料連接層效能比較

這篇文章的產生其實滿奇妙的,由於目前在前端維護MVC後台,理應碰不到ADO.NET層,偏偏資料連接層的速度又奇曼無比,甚至還會發出錯誤訊息。

在資料取得慢的情況下,所有後台的UI都極為緩慢,多數時候充當第一線砲灰。

在最近終於加入了幾位夥伴,於是協助後端同仁優化這段程式碼的念頭就產生了。

 

這篇文章會比較DataTable.Load、DataAdapter.Fill、DataReader三者的差異,一起來看看吧。

DataAdapter.FillDataReaderDataTable.Load三者差在哪裡呢?

DataAdapter是填入DataSet,將資料常駐在記憶體的一種方式

DataReader提供未緩衝處理的資料流的資料,讓程序邏輯有效地循序處理來自資料來源的結果。 DataReader擷取大量資料,因為資料不會快取記憶體時,是不錯的選擇。

DataTable.Load傳入IDataReader,並在內部執行DbDataAdapter.Fill,而DbDataAdapter則是繼承自DataAdapter

這樣看起來應比較的只有前二個,不過看在DataTable.Load處於一個滿奇妙的位置,於是也將DataTable.Load列入比較,畢竟要調整的是效能嘛XD


 

如果要了解ADO.NET,以下這二篇滿推薦的

ADO.NET的最佳實踐

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


LINE討論群FB討論區

歡迎您的加入,讓這個社群更加美好!

聯絡方式:
FaceBook
E-Mail