PDF.NET開發框架性能剖析


 

前倆天發布了 關於PDF.NET開發框架對Mysql Sqlite PostgreSQL數據庫分頁支持的個人看法 ,說明了本人對框架的一些介紹和看法。今天我們一起思考一些問題。

 

 

1.裝箱與拆箱

EntityBase.cs

 1 private object[] values;
 2 /// <summary>
 3 /// 屬性值列表
 4 /// </summary>
 5 public virtual object[] PropertyValues
 6 {
 7     get
 8     {
 9         if (values == null)
10         {
11             values = new object[PropertyNames.Length];
12         }
13         return values;
14     }
15     protected internal set { values = value; }
16 }

每個實體類對象,一般情況下相當於表中的一行數據。把屬性里封裝的字段放在數組中,字段有值類型(tinyint int double...) 引用類型,為了滿足各種類型只能由object類型出廠,這樣會導致值類型頻繁進行拆箱(引用類型到值類型--get)/裝箱(值類型到引用類型--set)操作.這在一定程度上,對性能造成了損耗。

 

2.for與foreach

CommonDB.cs

 1 if (parameters != null)
 2     for (int i = 0; i < parameters.Length; i++)
 3         if (parameters[i] != null)
 4         {
 5             if (commandType != CommandType.StoredProcedure)
 6             {
 7                 //IDataParameter para = (IDataParameter)((ICloneable)parameters[i]).Clone();
 8                 IDataParameter para = parameters[i];
 9                 if (para.Value == null)
10                     para.Value = DBNull.Value;
11                 cmd.Parameters.Add(para);
12             }
13             else
14             {
15                 //為存儲過程帶回返回值
16                 cmd.Parameters.Add(parameters[i]);
17             }
18         }

使用for循環,加數組的索引器使用(每調用一次,就循環一次,可以反編譯查看),會造成數組的重復遍歷。話不多說,看哥代碼,你懂得!

 1 if (parameters != null)
 2 {
 3     foreach (IDataParameter para in parameters)
 4     {
 5         if (para != null)
 6         {
 7             if (commandType != CommandType.StoredProcedure)
 8             {
 9                 if (para.Value == null)
10                     para.Value = DBNull.Value;
11                 cmd.Parameters.Add(para);
12             }
13             else
14             {
15                 //為存儲過程帶回返回值
16                 cmd.Parameters.Add(para);
17             }
18         }
19     }
20 }

 

3.雙重鎖定 double check

SqlCache.cs

 1 /// <summary>
 2 /// 增加一項到緩存中
 3 /// </summary>
 4 /// <param name="key"></param>
 5 /// <param name="item"></param>
 6 /// <returns></returns>
 7 public static bool AddToCache(string key,SqlInfo item)
 8 {
 9     SqlInfo Value = GetFromCache(key);
10     if (Value != null)
11         return false;
12     lock (sync_obj)
13     {
14         DictSqlCache.Add(key, item);
15     }
16     return true;
17 }

第一個if確實能減少鎖的影響,提示性能。 lock里需要做判斷的...看代碼

 1 /// <summary>
 2 /// 增加一項到緩存中
 3 /// </summary>
 4 /// <param name="key"></param>
 5 /// <param name="item"></param>
 6 /// <returns></returns>
 7 public static bool AddToCache(string key, SqlInfo item)
 8 {
 9     if (!DictSqlCache.ContainsKey(key))//在lock前判斷,有助於提升性能
10     {
11         lock (sync_obj)//假設2個線程同時執行到這,如果lock里不做判斷會出問題
12         {
13             if (!DictSqlCache.ContainsKey(key))
14             {
15                 DictSqlCache.Add(key, item);
16                 return true;
17             }
18         }
19     }
20     return false;
21 }

 

 

4.分頁

SqlPage.cs

 1 /// <summary>
 2 /// 根據主鍵的高效快速分頁之 升序分頁
 3 /// </summary>
 4 /// <param name="pageNum">頁碼,從1開始</param>
 5 /// <param name="pageSize">頁大小,大於1</param>
 6 /// <param name="filedList">字段列表</param>
 7 /// <param name="tableName">表名稱</param>
 8 /// <param name="PKName">主鍵名稱</param>
 9 /// <param name="conditon">查詢條件</param>
10 /// <returns>返回指定頁碼的快速分頁SQL語句</returns>
11 public static string GetAscPageSQLbyPrimaryKey(int pageNum, int pageSize, string filedList, string tableName, string PKName, string conditon)
12 {
13     if (conditon == null || conditon == "")
14         conditon = "1=1";
15     if (pageNum == 1)
16     {
17         string sqlTemplage = "Select top @pageSize @filedList from @table1 where  @conditon order by @PKName desc ";
18         return sqlTemplage
19             .Replace("@pageSize", pageSize.ToString())
20             .Replace("@filedList", filedList)
21             .Replace("@table1", tableName)
22             .Replace("@conditon", conditon)
23             .Replace("@PKName", PKName);
24     }
25     else
26     {
27         //@topNum= ((頁碼-1)*頁大小)
28         string sqlTemplage = @"
29 select top @pageSize @filedList
30 from @table1
31 where @conditon And @PKName>
32     (select max (@PKName) from
33     (select top @topNum @PKName from @table1 where @conditon order by @PKName asc) as T
34     )    
35 order by @PKName asc
36 ";
37         int topNum = (pageNum - 1) * pageSize;
38 
39         return sqlTemplage.Replace("@topNum", topNum.ToString())
40             .Replace("@pageSize", pageSize.ToString())
41             .Replace("@filedList", filedList)
42             .Replace("@table1", tableName)
43             .Replace("@conditon", conditon)
44             .Replace("@PKName", PKName);
45 
46     }
47 }
View Code

 

 首先,要把字符串對象構造為StringBuilder對象,用StringBuilder對象的Replace方法,這些細節和上篇也提到了,很多人會認為這是廢話,好吧......我不說廢話了,進入重點。

 

看了很多分頁代碼,有not in的,rownum偽列的,limit的。但如果只根據一列進行查詢,主鍵列或其他值類型的列均可,這種分頁無疑是性能最高的。個人很欣賞作者的代碼。

但是,我想提一個問題,

假如tableName參數傳入的是一個viewName(視圖名稱),

而這個視圖是有10張同結構的表,或不同結構的表抽取意義相同的列的數據  union而成。

這個視圖數據量百萬級數據量。這么寫能禁得住考驗嗎?

那么該如何改進呢?

相信clever的你已經懂了,若還沒想通,那就經歷3重境界吧:

   昨夜西風凋碧樹,獨上高樓,望盡天涯路。

   衣帶漸寬終不悔,為伊消得人憔悴。

   然后是驀然回首...........

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM