分享
 
 
 

基于性能的编程技巧点滴

王朝other·作者佚名  2006-02-01
窄屏简体版  字體: |||超大  

企业应用软件开发具有两个显著的特点:

(1)业务复杂;

(2)数据量大。

由这两个特点派生出另一特点——数据存储复杂。

在一般的结构或编程习惯下,我们总是尽量让程序的重用性尽可能高,算法的结构尽可能简单明了。基于这两点考虑,在程序中会尽量采用重载和多步处理的方法。这里所说的“多步处理”是指将一个对象,对象集或数据集进行二次处理得到满足需要的格式的结果。合理的多步处理会让程序的可读性明显增强。

首先,我们来看重载。勿庸置疑,重载使得程序本身的复用性大大提高,但不是每个重载都是最佳的设计。比如有这样一个简单问题:

例1

根据给定开始时间(dtBegin)和结束时间(dtEnd)来查询数据,假设查询语句类似“select A.somefields from A where A.fdBeginDate>=@dtBegin and A.fdEndDate<=@dtEnd”;

现在提供给用户的操作界面是两个时间可以不输入,即查询请求提交可能有三种情形:

不妨设用户查询接口为UserQuery;

UserQuery()

//没有查询条件;

UserQuery(dtBegin,-)

//只有开始时间;

UserQuery(-,dtEnd)

//只有结束时间;

UserQuery(dtBegin,dtEnd)

//指定每一时间;

这时的实现(重载)可这样表示

UserQuery()

//没有查询条件;

UserQuery(DateTime dtInput,bool bIsBegin)

//bIsBegin表示是否是开始时间,否则代表结束时间;

UserQuery(DateTime dtBegin,DateTime dtEnd)

//具体指定了每个查询条件;

现在我们给其中一个做具体实现,一般是UserQuery(DateTime dtBegin,DateTime dtEnd);而其他两个则变为

public DataSet UserQuery()

{

DateTime dtBegin = new DateTime(1900,1,1,0,0,0);

DateTime dtEnd = new DateTime(9999,12,31,23,59,59);

return UserQuery(dtBegin,dtEnd);

}

public DataSet UserQuery(DateTime dtInput, bool bIsBegin)

{

DateTime dtBegin;

DateTime dtEnd;

if(bIsBegin)

{

dtBegin = dtInput;

dtEnd = new DateTime(9999,12,31,23,59,59);

}

else

{

dtBegin = new DateTime(1900,1,1,0,0,0);

dtEnd = dtInput;

}

return UserQuery(dtBegin,dtEnd);

}

我们这里不讨论将(1900,1,1,0,0,0)设为最小时间和(9999,12,31,23,59,59)设为最大时间的合理性,只是举例说明很多情况下的条件查询我们会采用类似做法进行重载。

这种做法在结构和复用性都是不错的。但一旦查询的处理过程很复杂(如需要很多表之间的关联和筛选),则加一个条件的过滤即会耗费一定的时间,也就是说对于用户没有

指定条件的查询,如果硬套上一个边界条件,则会影响处理速度。实际上,我们可以对上面的写法做一些改进,把关于条件的判断加进实现函数里,即在采用下面的实现方法。

public DataSet UserQuery()

{

DateTime dtTemp = new DateTime(1900,1,1,0,0,0);

return UserQuery(dtTemp,dtTemp,false,false);

}

public DataSet UserQuery(DateTime dtInput, bool bIsBegin)

{

if(bIsBegin)

{

return UserQuery(dtInput,dtInput,true,false);

}

else

{

return UserQuery(dtInput,dtInput,false,true);

}

}

public DataSet UserQuery(DateTime dtBegin,DateTime dtEnd)

{

return UserQuery(dtBegin,dtEnd,true,true);

}

private DataSet UserQuery(DateTime dtBegin,DateTime dtEnd, bool bNeedBegin,bool bNeedEnd)

{

string strSQL = "select A.somefields from A where 1=1";

if(bNeedBegin)

{

strSQL += " and A.fdBeginDate>=@dtBegin";

}

if(bNeedEnd)

{

strSQL += " and A.fdEndDate<=@dtEnd";

}

//do some query

....

return a DataSet;

}

再来看第二点——多步处理。程序设计中如果能用一次数据库访问或对象方法调用就得到所需数据是很理想的情况,然而业务不可能总是那样简洁易操作的。在很多业务处理中存在大量的数据比较、数据转换,这些数据处理有时并不复杂但数据量会很大。比如根据一个ID到数据库查询一个字符串,这种查询不同于前面所讲的查询,是一种简单但频繁的查询。

来看这样一个例子:

例2

已知数据集DataSet1

{OBJ1_ID, OBJ1_NAME, OBJ2_ID, OBJ2_NAME}

现在要求根据DataSet1得到数据集DataSet2

{OBJ1_ID, OBJ1_NAME, OBJ2_ID, OBJ2_NAME, OBJ3_NAME, OBJ4_NAME}

假设这里获取OBJ3_NAME, OBJ4_NAME的过程很简单,就是根据OBJ1_ID, OBJ2_ID去拼一段SQL出来,然后连接数据库查询一下即可。按照这个思路,一般会提供两种方法供调用,形如:

QueryCaption(string strID)

//单参数;

QueryCaption(string[] strIDArr)

//数组参数;

数组参数可以用IN或OR将多次查询转成一次查询,这样当数据量大的时候可以减少数据库连接次数。但对于上面的例子,因为有两个字段(OBJ3_NAME, OBJ4_NAME)要取,所以至少还是要调用两次,而且还要后续处理。这时可以用Union来实现进一步的优化

假设取OBJ3_NAME、OBJ4_NAME的SQL分别为

SELECT TB_NAMELIB_3.NAME OBJ3_NAME FROM TB_NAMELIB_3 WHERE TB_NAMELIB_3.NAME_ID= OBJ1_ID;

SELECT TB_NAMELIB_4.NAME OBJ4_NAME FROM TB_NAMELIB_4 WHERE TB_NAMELIB_4.NAME_ID= OBJ2_ID;

下面用Union合成取数据过程

DataRowCollection objRows = DataSet1.Tables[0].Rows;

int iCount = objRows.Count;

string[] strSQLArr = new string[iCount];

string strSQL;

string strFields;

string strObjID1;

string strObjID2;

DataSet objDataSet;

for(int i=0;i<iCount;i++)

{

strObjID1 = objRows[i][“OBJ1_ID”].ToString();

strObjID2 = objRows[i][“OBJ2_ID”].ToString();

strFields = “’”+strObjID1 +"’ OBJ1_ID, ";

strFields+= “’”+objRows[i][“OBJ1_NAME”].ToString()+"’ OBJ1_NAME, ";

strFields+= “’”+strObjID2 +"’ OBJ2_ID, ";

strFields+= “’”+objRows[i][“OBJ2_NAME”].ToString()+"’ OBJ2_NAME, ";

strSQLArr[i] = " UNION SELECT "+ strFields +" TEMPU. OBJ3_NAME,TEMPJ.OBJ4_NAME, FROM (SELECT 1 PID, TB_NAMELIB_3.NAME OBJ3_NAME FROM TB_NAMELIB_3 WHERE TB_NAMELIB_3.NAME_ID="'"+ strObjID1 +""'") TEMPU LEFT JOIN (SELECT 1 PID, TB_NAMELIB_4.NAME OBJ4_NAME FROM TB_NAMELIB_4 WHERE TB_NAMELIB_4.NAME_ID= "'"+ strObjID2 +"'") TEMPJ ON TEMPU.PID = TEMPJ.PID UNION SELECT "+ strFields +" TEMPU.OBJ3_NAME,TEMPJ.OBJ4_NAME, FROM (SELECT 1 PID, TB_NAMELIB_3.NAME OBJ3_NAME FROM TB_NAMELIB_3 WHERE TB_NAMELIB_3.NAME_ID= "'"+ strObjID1 +"'") TEMPU RIGHTER JOIN (SELECT 1 PID, TB_NAMELIB_4.NAME OBJ4_NAME FROM TB_NAMELIB_4 WHERE TB_NAMELIB_4.NAME_ID= "'"+ strObjID2 +"'") TEMPJ ON TEMPU.PID = TEMPJ.PID ";

}

if(iCount>0)

{

if(null==strSQLArr[0])

{

return null;

}

strSQLArr[0] = strSQLArr[0].Substring(6);

strSQL = String.Concat(strSQLArr);

//创建连接 PersistConn m_objPersistConn = new PersistConn();

//执行查询 objDataSet = m_objPersistConn.ExecuteDataSet(strSQL);

//释放连接 m_objPersistConn.Dispose();

return objDataSet;

}

可以看到,这样一次SQL执行就可以得到目的数据集。这里不用Cross Join的原因是为了兼容有些数据库中不用Cross Join来表示全连接。在实际情况中类似这种问题其实很多,当然不一定问题描述完全一样。

以上通过两个简单的例子来说明实际编程中一些体会,类似这些点滴相信每个程序员都有自己的体会。我觉得优秀的代码就像学习英语一样,是慢慢积累起来的。近年来,有关性能编程方面的资料逐渐开始丰富起来。很多好的编程思路可以让我们得到很好的借鉴,同时我们还可以在实际开发中对其进行进一步拓展。比如:Lazy Loading的思想实际上可以应用到多层架构的多个面上,从数据实体到业务实体,再到UI层。

另外一个比较重要的问题是:如何在“有限”的情况下检验程序的性能。这里的“有限”是指不能够快速地使系统具有超大数据量或者复杂度。这时,我们可以考虑进行“逆境测试”,即通过降低Server的配置或程序的简单修改从而能够在某种程度上模拟出一些性能问题。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有