优化你的PowerBuilder程序

PowerBuilder是快速有效开发工具,在实现过程灵活
多样,下面介绍下在开发高校产品过程中积累些经验
、处理 SQL 语句

1、缓冲 SQL 语句
在应用有时需要反复组 SQL语句
在这种情况下可以通过在应用中为这些 SQL 建立缓冲区来
提高执行性能
在缺省情况下SQL 语句缓冲区是关闭你可以
通过如下语句打开它:
SQLCACHE = n
n 表示装入缓冲区 SQL 语句数量(缺省为0)
例如:
dw_1.SetTransObject(sqlca)
SQLCA.dbParm = "SQLCache = 0"
dw_1.retrieve

如果将上例 "SQLCache = 0" 改为 "SQLCache = 25"
此句执行效率将提高 5分的左右但应注意缓冲区大小,
否则也将影响执行性能
注:此思路方法对用 ODBC 和 ORACLE 连接数据库非常有效

2、捆绑变量
请看下例:
SQLCA.DBPARM = "DISABLEBIND=1"

INSERT INTO DA_DH VALUES("1","河南0")
INSERT INTO DA_DH VALUES("2","河南1")
INSERT INTO DA_DH VALUES("3","河南2")
INSERT INTO DA_DH VALUES("4","河南3")
INSERT INTO DA_DH VALUES("5","河南4")
INSERT INTO DA_DH VALUES("6","河南5")

这里未使用捆绑变量在插入是 PB 将重新处理每个带有
新值SQL语句如果将上例改为:
SQLCA.DBPARM = "DISABLEBIND=0"

INSERT INTO DA_DH VALUES("1","河南0")
INSERT INTO DA_DH VALUES("2","河南1")
INSERT INTO DA_DH VALUES("3","河南2")
INSERT INTO DA_DH VALUES("4","河南3")
INSERT INTO DA_DH VALUES("5","河南4")
INSERT INTO DA_DH VALUES("6","河南5")

则系统将把 INSERT 语句按如下格式进行处理:
INSERT INTO DA_DH VALUES(?,?)
其中 "?" 称为占位符系统性能将有所增强
3、用数据窗口代替 SQL 语句

通常为了获得某些数据采用数据窗口和 SQL 语句都是可行
但是PB 对数据窗口和 SQL 语句采用区别处理机制因此
具有区别效率

例:为里检索电话档案中用户名可以利用 SQL 语句

将所有数据检索到个多行编辑中也可以检索到个数据窗口中
如果使用第中思路方法:
首先定义个游标:

DECLARE CUR CURSOR FOR
SELECT "DA_DH"."HM"
FROM "DA_DH";
然后可以:

STRING stxt,st
li

open cur
do li = li + 1
fetch cur
o :stxt[li] ;
st=st+stxt[li] + "~r~n"
loop while stxt[li]""
close cur;
mle_1.txt = st

也可以使用第 2种思路方法:
dw_1.transobject(sqlca)
dw_1.retrieve
利用 POWERBUILDER PROFILER 工具进行检查对比两种
思路方法所需时间如下
思路方法 所需时间 (百分的秒)
SQL 语句    100.9857
数据窗口 49.0133

  由于数据窗口或 DATASTORE 使用了标准内嵌代码
而不是有开发人员进行全部编码同时编译执行速度比解释
执行速度快因此在开发过程中应尽量使用数据窗口和
DATASTORE.. 即使是必须用 SQL 语句时候也应该尽量
将它们定义为存储过程(特别是在多用户环境中)以提高
应用性能.


2、数据窗口编程和执行

数据窗口是PB最值得被称道, 其具有如下特点:
1. 多种显示方式.
2. 多种编辑方式.
3. 使用思路方法简单.
4. 具有多种报表形式.
5. 可实现屏幕滚动.
6. 可实现数据有效性校验.
7. 执行性能显著提高.
8. 编程工作变少.
9. 可以在数据窗口内部实现数据哭更新.

下面, 我将介绍些用于提高数据窗口性能技术.


1. 减少连接数据库次数

连库操作是非常影响执行速度操作. 因此在中,旦和数据库连接后
就应当尽量保持和数据库连接, 减少连接数据库次数.
PowerBuilder 提供里两个来建立数据窗口和事务对象连接:
SetTrans
SetTransObject
中应当尽量使用 SETTRANSOBJECT, SETTRANS 在每次
RETRIEVE, UPDATE的后, 都要执行数据库连接和断开操作.

2. 下拉数据窗口和表连接

对于数据库服务器来说, 表连接操作是项非常大开销, 而 POWERBUILDER 提供下拉数据窗口在某些情况下可以代替表连接操作.

例如, 为了在数据窗口上显示用户电话号码和姓名:
如果用表连接思路方法, 数据窗口对应 SQL 语句应是这样:
SELECT "DA_DH"."DHHM",
"DA_HTH"."DWM"
FROM "DA_HTH",
"DA_DH"
WHERE ("DA_HTH"."DHHM"="DA_DH"."DHHM")
同样可用下拉数据窗口来完成, 这里不再具体介绍.
但是, 应当注意, 以上两种思路方法究竟哪种数据更快, 和表结构, 表
数量, 连接思路方法等均有关系, 应当具体分析.
3. 共享数据
个应用中, 某些数据需要频繁使用, 如果在每次使用时都从数据库
中进行检索, 则需占用大量服务器资源和网络资源. 为了减少开销, 可以在客户
端对这些数据只进行次检索, 然后允许其它任务共享这些数据.

例如, 如果有两个数据窗口, 都需要从第 3方表中检索出用户电话号码, 且此
列用下拉数据窗口给出. 如果每次都对电话号码进行检索, 则性能较低. 因此, 可
以单独建立个有关电话号码数据窗口. 在每次打开窗口时, 首先将电话号码检
索到此数据窗口中, 然后另外两个数据窗口中有关电话号码下拉数据窗口可以共享
此数据窗口中数据.

在窗口 OPEN 事件中编写如下:

dw_1.transobject(sqlca)
dw_2.transobject(sqlca)
dw_3.transobject(sqlca)
// 检索 dw_1
dw_1.retrieve

// 使 DW_2 下拉数据窗口共享 DW_1
datawindowchild child1
dw_2.getchild('dhhm',child1)
child1.transobject(sqlca)
dw_1.sharedata(child1)

// 使 DW_3 下拉数据窗口共享 DW_1
datawindowchild child2
dw_3.getchild('dhhm',child2)
child2.transobject(sqlca)
dw_1.sharedata(child2)
使用这种思路方法, 避免了各个数据窗口间物理拷贝数据, 因此减少了空间上开销,提高了应用综合性能.


4. 数据窗口间数据拷贝

如果需要在数据窗口间共享数据, 应当尽量使用 SHAREDATA , 但是,
SHAREDATA 并不是物理地在数据窗口间拷贝数据, 如果在显示数据同时, 还
要对数据进行操作, 则需要进行数据拷贝.

例如, 要求将 DW_1 中选定行拷贝到 DW_2 中:

在窗口 OPEN 事件中编程:
dw_1.transobject(sqlca)
dw_2.transobject(sqlca)
dw_1.retrieve

在数据窗口 DW_1 ROWFOCUSCHANGED 事件中编写下列:
long lr
lr = dw_1.selectrow(0,false)
lr = dw_1.getrow
lr = dw_1.selectrow(lr,true)

要完成从 DW_1 到 DW_2 拷贝工作, 有两种思路方法:


种:
在按钮 "拷贝" CLICKED 事件中编程

long lr
lr = dw_1.getselectedrow(0)
dw_1.rowscopy(lr,lr,primary!,dw_2,100,primary!)

执行, 利用 POWERBUILDER PROFILER 得出所需时间为 1.7034(百分的秒)

第 2种:
在按钮 "拷贝" CLICKED 事件中编程

dw_2.object.data = da_1.object.data.selected

执行, 利用 POWERBUILDER PROFILER 得出所需时间为 0.8062(百分的秒)

5. 数据窗口属性访问和修改


A. 数据窗口属性访问
中访问数据窗口属性有下列几种思路方法:

A1. 采用点表达式访问
A2. 应用多个独立 DESCRIBE 访问
A3. 只使用个 DESCRIBE , 采用复合参数访问多个属性

上面 3中思路方法, 通常第种思路方法最慢, 第 3种思路方法最快.

例如:
在窗口 OPEN 事件中
DW_1.SETTRANSOBJECT(SQLCA)
DW_1.RETRIEVE

种思路方法:
在检索按钮 CLICKED 事件中编程.

dx, dy, dh, dw
dx = dw_1.object.da_dh.x
dy = dw_1.object.da_dh.y
dx = dw_1.object.da_dh.height
dy = dw_1.object.da_dh.width

st_1.text =dx+","+dy+","+dh+","+dw

第 2种思路方法:
dx, dy, dh, dw
dx=dw_1.describe("da_dh.x")
dx=dw_1.describe("da_dh.y")
dx=dw_1.describe("da_dh.height")
dx=dw_1.describe("da_dh.width")

st_1.text =dx+","+dy+","+dh+","+dw

第 3种思路方法:
dx, dy, dh, dw
st_1.text=dw_1.describe("da_dh.x" +&

"da_dh.y" +&
"da_dh.height" +&
"da_dh.width")

实验证明, 第 3种思路方法速度是最快. 但是可读性最差.


B. 数据窗口属性修改
中修改数据窗口属性有下列几种思路方法:

A1. 采用点表达式修改
A2. 应用多个独立 MODIFY 访问
A3. 只使用个 MODIFY , 采用复合参数访问多个属性

上面 3中思路方法, 通常第种思路方法最慢, 第 3种思路方法最快.

例如:
在窗口 OPEN 事件中
DW_1.SETTRANSOBJECT(SQLCA)
DW_1.RETRIEVE

种思路方法:
在检索按钮 CLICKED 事件中编程.

DW_1.SETREDRAW(FALSE)
dw_1.object.da_dh.x = 18
dw_1.object.da_dh.y = 16
dw_1.object.da_dh.height = 100
dw_1.object.da_dh.width = 200
DW_1.redraw(true)
st_1.text =dx+","+dy+","+dh+","+dw

第 2种思路方法:
DW_1.SETREDRAW(FALSE)
dw_1.mody("da_dh.x = 18")
dw_1.mody("da_dh.y = 16")
dw_1.mody("da_dh.height = 100")
dw_1.mody("da_dh.width = 200")
dw_1.redraw(true)

第 3种思路方法:
dw_1.mody("da_dh.x=18" +&
"da_dh.y=16" +&
"da_dh.height=100" +&
"da_dh.width=200")

实验证明, 第 3种思路方法速度是最快. 但是可读性最差.
注意, 在思路方法和思路方法 2中, 都使用 redraw 以减少
屏幕重绘, 否则, 执行速度将严重下降.

6. 数据窗口中数据访问

中, 经常会需要动态修改数据窗口中数据. 对此, PB
提供了多种思路方法, 各种思路方法在性能上会有些差异.

A. 数据窗口中数据访问

: 将数据窗口中电话号码存放在中.
请比较下面两中思路方法.
思路方法:
da_dh
long ll,i
ll = dw_1.rowcount
for i = ll to 1 stet -1
da_dh = dw_1.getitem(i,"dhhm")
next
思路方法 2:
da_dh
da_dh = dw_1.object.dhhm.current

测试发现, 第 2种思路方法比第种思路方法快将近倍. 数据量越大
这种差异越明显.

B. 数据窗口中数据修改

: 修改数据窗口中电话号码列值.
请比较下面两中思路方法.
思路方法:
dw_1.item(i,"dhhm",l_name)
思路方法 2:
dw_1.object.name = l_name

测试发现, 第 2种思路方法比第种思路方法快将近倍. 数据量越大
这种差异越明显.

7. 数据窗口事件对性能影响

对于数据窗口控制中经常发生事件, 应当尽量减少其中代码.
特别是如下事件:
A. itemchanged
b. editchanged
c. itemfocuschanged
d. pbm_dwnkey
e. rowfocuschanged
f. retrieverow
在这些事件中任何处理, 都会降低应用处理速度. 所以
应当尽量减少这些事件中处理, 必要时, 可以考虑只将重要代码
放在这些事件中, 而将剩余代码放在个传递事件中.

例如如果需要用到数据窗口 ROWFOCUSCHANGED 事件可以为数据
窗口定义用户事件 "UE_RE", 而在数据窗口 ROWFOCUSCHANGED 事件
中写如下代码:

PARENT.postevent("ue_re")
在 UE_RE 事件中再编写相应代码如:
code
dw_1.selectrow(0,false)
dw_1.selectrow(rownum,true)
code = getitem(dw_1,rownum,"dhhm")

dw_2.retrieve(code)

另外 为了获得当前行号应尽量使用数据窗口 CURRENTROW 变量
而少用 GETROW()

8、 数据窗口列名称和列编号

对数据窗口某列进行访问 可以采用该列名称 也可以使用该列编号
例如:
采用列编号:

dw_1.object.data[ll_row,2]
dw_1.getitem(3,2)

采用列名称表示某列:

dw_1.object.article_text[ll_row]
dw_1.getitem(3,"dhhm")
dw_1.item(3,"date",1999-03-31)
...
对于以上两种思路方法 如果只进行次查询 在速度上并没有太大区别
如过需要循环访问数据窗口上 则速度上差异就表现比较明显
才用第种思路方法要快 但是可读性比较差
但是 在使用时(如 GETITEMitem ) 执行速度往往
没有很大差别

9、 计算域

数据窗口计算域会对数据操作性能产生影响 如果数据窗口中包含许多
复杂计算域将严重影响数据窗口执行速度
Tags: 

延伸阅读

最新评论

发表评论