知道方法有很多,我就自己懂的部分,寫下純 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 則留言:
謝謝分享!
張貼留言