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
/// <summary>
/// 根据主键的高效快速分页之 升序分页
/// </summary>
/// <param name="pageNum">页码,从1开始</param>
/// <param name="pageSize">页大小,大于1</param>
/// <param name="filedList">字段列表</param>
/// <param name="tableName">表名称</param>
/// <param name="PKName">主键名称</param>
/// <param name="conditon">查询条件</param>
/// <returns>返回指定页码的快速分页SQL语句</returns>
public static string GetAscPageSQLbyPrimaryKey(int pageNum, int pageSize, string filedList, string tableName, string PKName, string conditon)
{
if (conditon == null || conditon == "")
conditon = "1=1";
if (pageNum == 1)
{
string sqlTemplage = "Select top @pageSize @filedList from @table1 where @conditon order by @PKName desc ";
return sqlTemplage
.Replace("@pageSize", pageSize.ToString())
.Replace("@filedList", filedList)
.Replace("@table1", tableName)
.Replace("@conditon", conditon)
.Replace("@PKName", PKName);
}
else
{
//@topNum= ((页码-1)*页大小)
string sqlTemplage = @"
select top @pageSize @filedList
from @table1
where @conditon And @PKName>
(select max (@PKName) from
(select top @topNum @PKName from @table1 where @conditon order by @PKName asc) as T
)
order by @PKName asc
";
int topNum = (pageNum - 1) * pageSize;
return sqlTemplage.Replace("@topNum", topNum.ToString())
.Replace("@pageSize", pageSize.ToString())
.Replace("@filedList", filedList)
.Replace("@table1", tableName)
.Replace("@conditon", conditon)
.Replace("@PKName", PKName);
}
}
首先,要把字符串对象构造为StringBuilder对象,用StringBuilder对象的Replace方法,这些细节和上篇也提到了,很多人会认为这是废话,好吧......我不说废话了,进入重点。
看了很多分页代码,有not in的,rownum伪列的,limit的。但如果只根据一列进行查询,主键列或其他值类型的列均可,这种分页无疑是性能最高的。个人很欣赏作者的代码。
但是,我想提一个问题,
假如tableName参数传入的是一个viewName(视图名称),
而这个视图是有10张同结构的表,或不同结构的表抽取意义相同的列的数据 union而成。
这个视图数据量百万级数据量。这么写能禁得住考验吗?
那么该如何改进呢?
相信clever的你已经懂了,若还没想通,那就经历3重境界吧:
昨夜西风凋碧树,独上高楼,望尽天涯路。
衣带渐宽终不悔,为伊消得人憔悴。
然后是蓦然回首...........