本文沒啥技術含量,就是測試一下 MSSqlHelper 在 使用反射、不使用反射 的性能對比。 之後,不要問為什麼不用 ORM 這類的東西 —— 會有另外的文章 介紹 自己這些年 自己的ORM 升級歷史。 背景: 我自己有一個 MSSqlHelper, 這個 輔助類 是最基本的一個 資料庫操作類。 ...
本文沒啥技術含量,就是測試一下 MSSqlHelper 在 使用反射、不使用反射 的性能對比。
之後,不要問為什麼不用 ORM 這類的東西 —— 會有另外的文章 介紹 自己這些年 自己的ORM 升級歷史。
背景:
我自己有一個 MSSqlHelper, 這個 輔助類 是最基本的一個 資料庫操作類。
Query 查詢集合時,可以指定 reader => 對象 的委托 —— 如果不指定,則 MSSqlHelper 會自動通過反射賦值。
static void Main(string[] args) { Test0(); Test1(); Test0(); Test1(); Console.ReadKey(); } public static void Test0() { string connString = "Data Source=localhost;Initial Catalog=InkFxBlog;User Id=sa; Pwd=123.com;"; DateTime time0 = DateTime.Now; List<TS_SDK> list = MSSqlHelper.Query<TS_SDK>(connString, "SELECT * FROM dbo.TS_SDK"); DateTime time1 = DateTime.Now; Console.WriteLine("Test0 | " + list.Count + " | " + (time1 - time0).TotalSeconds + "秒"); } public static void Test1() { string connString = "Data Source=localhost;Initial Catalog=InkFxBlog;User Id=sa; Pwd=123.com;"; DateTime time0 = DateTime.Now; List<TS_SDK> list = MSSqlHelper.Query<TS_SDK>(connString, "SELECT * FROM dbo.TS_SDK", null, reader => { TS_SDK item = new TS_SDK(); item.FId = (Int64)reader["FId"]; item.FNumber = (string)reader["FNumber"]; item.FEnum = (string)reader["FEnum"]; item.FName = (string)reader["FName"]; item.FSDKName = (string)reader["FSDKName"]; item.FFullName = (string)reader["FFullName"]; item.FType = (string)reader["FType"]; item.FVisit = (string)reader["FVisit"]; item.FInheritFrom = (string)reader["FInheritFrom"]; item.FJoinBaseType = (string)reader["FJoinBaseType"]; item.FJoinChildType = (string)reader["FJoinChildType"]; item.FIsStatic = (Boolean)reader["FIsStatic"]; item.FIsOverride = (Boolean)reader["FIsOverride"]; item.FIsVirtual = (Boolean)reader["FIsVirtual"]; item.FIsAbstract = (Boolean)reader["FIsAbstract"]; item.FIsInherit = (Boolean)reader["FIsInherit"]; item.FIsNetFx = (Boolean)reader["FIsNetFx"]; item.FOutUrl = (string)reader["FOutUrl"]; item.FSummary = (string)reader["FSummary"]; item.FRtSummary = (string)reader["FRtSummary"]; item.FCSCode = (string)reader["FCSCode"]; item.FVBCode = (string)reader["FVBCode"]; item.FCPPCode = (string)reader["FCPPCode"]; item.FFSCode = (string)reader["FFSCode"]; item.FAssembly = (string)reader["FAssembly"]; item.FVersion = (string)reader["FVersion"]; item.FNameSpace = (string)reader["FNameSpace"]; item.FParentId = (Int64)reader["FParentId"]; item.FParentNumber = (string)reader["FParentNumber"]; item.FDemo = (string)reader["FDemo"]; item.FInfo = (string)reader["FInfo"]; return item; }); DateTime time1 = DateTime.Now; Console.WriteLine("Test1 | " + list.Count + " | " + (time1 - time0).TotalSeconds + "秒"); }
運行結果:
讀取了全表 7W行記錄。
—— 很明顯:沒有指定 reader 讀取的委托、使用內置的反射代碼 足足慢了 3秒。
—— 當然,MSSqlHelper 內置的委托 進行了穩定性控制,使用了 這類代碼:
item.FId = Tools.ToLong(reader["FId"]); item.FName = Tools.ToString("FName");
這類轉換函數,性能肯定沒有 下麵的代碼 性能快:
item.FId = (Int64)reader["FId"]; item.FName = (string)reader["FName"];
我為什麼死活堅持 Tools 提供的 類型強轉?
> 因為穩定
> 轉換範圍廣 : 相容下麵這類 變態資料庫數據
//這是 瀏覽器的 時間格式,以下代碼 能得到 2017-03-20 02:46:06 000 DateTime timeA = Tools.ToDateTime("Mon Mar 20 2017 02:46:06 GMT+0800 (中國標準時間)"); //以下代碼 能得到 2017-03-19 01:43:15 000 DateTime timeA = Tools.ToDateTime("2017年3月19日 01時43分15秒");
我們再使用 Tools 的類型強轉函數 試一試,看一下 Tools 的類型轉換會浪費多少性能
public static void Test2() { string connString = "Data Source=localhost;Initial Catalog=InkFxBlog;User Id=sa; Pwd=123.com;"; DateTime time0 = DateTime.Now; List<TS_SDK> list = MSSqlHelper.Query<TS_SDK>(connString, "SELECT * FROM dbo.TS_SDK", null, reader => { TS_SDK item = new TS_SDK(); //這次的 reader 委托, //類型轉換 使用的 Tools.ToLong() Tools.ToLong() 這類函數 //為什麼不直接用 (string)reader["FName"] 這類直接轉換 ? —— 為了穩定性、我寧願犧牲性能 item.FId = Tools.ToLong(reader["FId"]); item.FNumber = Tools.ToString(reader["FNumber"]); item.FEnum = Tools.ToString(reader["FEnum"]); item.FName = Tools.ToString(reader["FName"]); item.FSDKName = Tools.ToString(reader["FSDKName"]); item.FFullName = Tools.ToString(reader["FFullName"]); item.FType = Tools.ToString(reader["FType"]); item.FVisit = Tools.ToString(reader["FVisit"]); item.FInheritFrom = Tools.ToString(reader["FInheritFrom"]); item.FJoinBaseType = Tools.ToString(reader["FJoinBaseType"]); item.FJoinChildType = Tools.ToString(reader["FJoinChildType"]); item.FIsStatic = Tools.ToBoolean(reader["FIsStatic"]); item.FIsOverride = Tools.ToBoolean(reader["FIsOverride"]); item.FIsVirtual = Tools.ToBoolean(reader["FIsVirtual"]); item.FIsAbstract = Tools.ToBoolean(reader["FIsAbstract"]); item.FIsInherit = Tools.ToBoolean(reader["FIsInherit"]); item.FIsNetFx = Tools.ToBoolean(reader["FIsNetFx"]); item.FOutUrl = Tools.ToString(reader["FOutUrl"]); item.FSummary = Tools.ToString(reader["FSummary"]); item.FRtSummary = Tools.ToString(reader["FRtSummary"]); item.FCSCode = Tools.ToString(reader["FCSCode"]); item.FVBCode = Tools.ToString(reader["FVBCode"]); item.FCPPCode = Tools.ToString(reader["FCPPCode"]); item.FFSCode = Tools.ToString(reader["FFSCode"]); item.FAssembly = Tools.ToString(reader["FAssembly"]); item.FVersion = Tools.ToString(reader["FVersion"]); item.FNameSpace = Tools.ToString(reader["FNameSpace"]); item.FParentId = Tools.ToLong(reader["FParentId"]); item.FParentNumber = Tools.ToString(reader["FParentNumber"]); item.FDemo = Tools.ToString(reader["FDemo"]); item.FInfo = Tools.ToString(reader["FInfo"]); return item; }); DateTime time1 = DateTime.Now; Console.WriteLine("Test2 | " + list.Count + " | " + (time1 - time0).TotalSeconds + "秒"); }
再測試一下:
—— 近期想把自己的底層輔助類 再優化一下,所以把代碼翻出來,折騰一下 ~
----------------------------------------------------------------------------------------------------------------------------------------
剛剛修改了一下 反射的代碼,啟用了 Emit 高速反射
性能果然得到了 明顯提升,性能僅損失 15 ~20% —— 我已經知足了。
Ps. 目前的 Emit反射 使用的通用代碼(內外一個輔助類) —— 如果針對性的寫 Emit 代碼,性能還能再次提升,但我懶得寫。
----------------------------------------------------------------------------------------------------------------------------------------
增加了一個 最原生寫法 —— 也就是 性能極限
public static void TestSouce() { string connString = "Data Source=localhost;Initial Catalog=InkFxBlog;User Id=sa; Pwd=123.com;"; DateTime time0 = DateTime.Now; List<TS_SDK> list =new List<TS_SDK>(); using (SqlConnection conn = new SqlConnection(connString)) { conn.Open(); using (SqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT * FROM dbo.TS_SDK"; using (SqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { TS_SDK item = new TS_SDK(); item.FId = (Int64)reader["FId"]; item.FNumber = (string)reader["FNumber"]; item.FEnum = (string)reader["FEnum"]; item.FName = (string)reader["FName"]; item.FSDKName = (string)reader["FSDKName"]; item.FFullName = (string)reader["FFullName"]; item.FType = (string)reader["FType"]; item.FVisit = (string)reader["FVisit"]; item.FInheritFrom = (string)reader["FInheritFrom"]; item.FJoinBaseType = (string)reader["FJoinBaseType"]; item.FJoinChildType = (string)reader["FJoinChildType"]; item.FIsStatic = (Boolean)reader["FIsStatic"]; item.FIsOverride = (Boolean)reader["FIsOverride"]; item.FIsVirtual = (Boolean)reader["FIsVirtual"]; item.FIsAbstract = (Boolean)reader["FIsAbstract"]; item.FIsInherit = (Boolean)reader["FIsInherit"]; item.FIsNetFx = (Boolean)reader["FIsNetFx"]; item.FOutUrl = (string)reader["FOutUrl"]; item.FSummary = (string)reader["FSummary"]; item.FRtSummary = (string)reader["FRtSummary"]; item.FCSCode = (string)reader["FCSCode"]; item.FVBCode = (string)reader["FVBCode"]; item.FCPPCode = (string)reader["FCPPCode"]; item.FFSCode = (string)reader["FFSCode"]; item.FAssembly = (string)reader["FAssembly"]; item.FVersion = (string)reader["FVersion"]; item.FNameSpace = (string)reader["FNameSpace"]; item.FParentId = (Int64)reader["FParentId"]; item.FParentNumber = (string)reader["FParentNumber"]; item.FDemo = (string)reader["FDemo"]; item.FInfo = (string)reader["FInfo"]; list.Add(item); } } } } DateTime time1 = DateTime.Now; Console.WriteLine("TestSouce | " + list.Count + " | " + (time1 - time0).TotalSeconds + "秒"); }