知道方法有很多,我就自己懂的部分,寫下純 ADO.NET 的作法,先以 DataTable 的 ToTable 方法取得 distinct 過的群組鍵,接下來建立 Relation 關連回原 DataTable,最後利用在群組鍵 DataTable 中增加自動計算欄位 (Expression 屬性,透過 DataColumnCollection.Add method 設定) 完成關聯記錄的計算
見範例程式中 TestByPureAdoNet method 中
我知道 LINQ to DataSet 能幫我做到一樣的事情,但是僅停留在大概知道怎麼做的階段,雖然同事的 .NET 2.0 環境也用不上,還是借機小練了一下,這才發現效能差距不小...
LINQ 的作法可以從範例中的 TestByLinq method 看到
using System; using System.Linq; using System.Data; using System.Diagnostics; class Program { static void Main(string[] args) { Stopwatch stopWatch = new Stopwatch(); Console.WriteLine("Testing by pure ADO.NET..."); stopWatch.Start(); TestByPureAdoNet(); stopWatch.Stop(); Console.WriteLine(stopWatch.ElapsedMilliseconds + "ms"); Console.WriteLine("Testing by LINQ..."); stopWatch.Reset(); stopWatch.Start(); TestByLinq(); stopWatch.Stop(); Console.WriteLine(stopWatch.ElapsedMilliseconds + "ms"); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } private static void TestByPureAdoNet() { for (int i = 0; i < 10000; i++) { DataSet ds = GetDataSet(); DataTable dt = ds.Tables[0]; // 分組並計算 DataTable grouped = dt.DefaultView.ToTable("DistinctTable", true, new[]{"GroupKey"}); ds.Tables.Add(grouped); ds.Relations.Add("Relation1", grouped.Columns["GroupKey"], dt.Columns["GroupKey"]); grouped.Columns.Add("SumValue", typeof(int), "Sum(Child.Value)"); foreach (DataRow dr in grouped.Rows) { var key = dr["GroupKey"]; var value = dr["SumValue"]; if (i == 0) System.Console.WriteLine(key + " = " + value); } } } private static void TestByLinq() { for (int i = 0; i < 10000; i++) { DataSet ds = GetDataSet(); DataTable dt = ds.Tables[0]; // 分組並計算 var grouped = from row in dt.AsEnumerable() group row by row["GroupKey"] into g select new { GroupKey = g.Key, SumValue = g.Sum(p => (int)p["Value"]) }; foreach (var group in grouped) { var key = group.GroupKey; var value = group.SumValue; if (i == 0) System.Console.WriteLine(key + " = " + value); } } } // 產生測試資料集 public static DataSet GetDataSet() { DataSet ds = new DataSet(); DataTable dt = new DataTable(); dt.Columns.Add("GroupKey", typeof(String)); dt.Columns.Add("Value", typeof(int)); ds.Tables.Add(dt); dt.Rows.Add(new object[] { "P1", 10 }); dt.Rows.Add(new object[] { "P2", 40 }); dt.Rows.Add(new object[] { "P3", 50 }); dt.Rows.Add(new object[] { "P1", 20 }); dt.Rows.Add(new object[] { "P2", 5 }); return ds; } }
最後既然 method 都實做了,當然要來量測一下效能,在 main 中使用 Stopwatch 取得測試 method 的執行花費時間,每個測試 method 中均反覆執行 10000 次以放大效能表現數值,發現以 LINQ to DataSet 進行查詢的效能平均約為純 ADO.NET 方式的 5~6 倍!
不過這種作業要反覆執行這麼多次的機會並不高,如果僅執行一次而言,initial cost + 執行時間,兩者相當,以我測試環境下測得均為 3ms
感嘆 LINQ 果然是好物啊!見到發明人 Anders Hejlsberg 快拜就對了!
參考資料:
101 LINQ Samples
1 則留言:
謝謝分享!
張貼留言