编码提示与优化技巧
已有 634 次阅读2007-9-2 23:20
|个人分类:我的作品
1. 使用Option Explicit
一定要使用Option Explicit。Option Explicit 要求确定所有变量的大小,要不然VBA就会用最大、最灵活的数据类型来保存变量。通常来讲,规模很大、灵活性很强的应用也是最慢的。
2. 慎重选择变量大小
在确定变量大小时,使用尽可能最小的变量尺寸。在整型就可以时不要使用双精度型,可能情况下使用固定长度字符串而不要使用可变长度字符串。
3. 使用字符串变量以节省堆栈空间
字符串变量是代码中最常用的一种数据类型,它们可以被分解成三种类型:
. 局部固定长度(长度不超过64个字符)——这些字符串每个字符仅用两个字节,而且不使用堆空间。
. 局部固定长度(长度超过65个字符)——这些字符串每个字符仍然使用两个字节,但是在堆内存中。同时,它们还要求堆栈中的四个字节来指向堆中的变量。
.局部可变量长度(长度一限)——堆空间的数量依存字符串长度而定。四字节的堆栈内存被用指向堆中变量的指针。
在处理字符串时,目标就应该是减少正在使用的堆栈内存。尝试着把字符串转换成局部可变长度或静态固定长度字符串。下面的代码段举说明为了节省堆栈内存而把内存而把可变长度字符串重新声明为静态固定长度字符串。
Dim strstring as string
Static strstring as string*30
提示:用表的字段大小来决定固定宽度文本字符串的长度
4.特写的对象类型声明
在声明对象变量时要精确。如果代码将要运行经过窗体的文本框控件,声明对象变量为文本框,而不要仅仅声明为控件。这样,VBA不必确定到底说的是哪种控件。例如:可以用
Sub CycleControls (cntl as TextBox)
代替
Sub CycleControls (cntl as control)
来节省运行时间。
5.切换True 和 False
在把一个标志位从True 翻转到 False 时,没有必要用一个IF…Then…Else结构来完成检查值标志的任务。可以用NOT操作符把值翻转,从而节省时间和代码。通过设定一个布尔变量为该变量的非,就可以翻转它。
可以用
bFlag=Not bFlag
代替
If bFlag=False then
bFlag=True
Else
bFlag=False
End IF
运行一行代码比运行几行计算要节省许多时间。
6.用Len()的函数代替空字符串
为了测试一个字符串变量中是否含有字符,应该使用Len函数而不是把字符串变量和空字符串(”” “”)进行比较。用Len计算比将变量和空字符串进行比较更快。
Sub CheckString (strString as string)
If Len(strString) then
MsgBox “Here is the string : “ & strString
End if
End Sub
7.用True 和 False 代替Zero
因为True 和False是二进进制的,它们比数字Zero更容易求值。可以像下面这样使用True和False:
Function ShowNumber(dblNumber as Double) as string
If dblNumber then
ShowNumber=”The number is “ & dblNumber
End if
End Function
8.快速对象引用
使用变量而不是重复的对象引用。引用一个在窗体、控件、报表或查询中存在的变量比再回头引用这个对象更快。代替再次引用窗体
Forms![frmMyForm].Height=500
Forms![frmMyForm].Width=500
可以尝试声明一个变量并按下面这样的引用它:
Dim Frm as Form
Set Frm =Forms![frmMyForm]
Frm.Height=500
Frm.Width=500
在处理一个对象的多个属性时,用With…End With来减少对象的引用。这在路径和引用很长时特别有用,而且也容易录入
With Forms![frmMainForm]![txtCustomerName]
.left=200
.top=300
.height=200
.width=100
End with
其中ME代表活动窗体,所以它直接指向当前窗体,省略了确定变量大小和声明对象变量。因为它只在CBF中有效,所以不能把它用在一般的标模块中,例如:
With ME
.Height=500
.Width=500
End With
9.快速数组使用
要使用数组。在一般情况下,数组驻留在内存中,对其防问和操作都很快。数组的扩大所需的时间无穷小,并且它们对内存使作效率极高。假如在开发过程中数组的大小没有确定,那么可使用动态数组。动态数组在运行时可以根据需要重新定义维数。千万不要声明一个浪费内存的大型静态数组。
用Erase 关键字可以清空数组而不破坏它的结构。Erase清空数组的内容,但不完全删除它。
Erase myArray
相反地,需要扩大一个数组但不破坏它的内容时可以用Redim 和Preserve。
ReDim Preserve myArray (Ubound(myArray+1))
数组存储的数据可以来自已记录集、控件组,也可以读自文件、用户输入以及任何一致的数据。例如,与其保持DAO记录集打开而招致相关的开销,不如打开数组后用GetRow()方法来产生一个合适的专用数组,然后释放记录集,这样可以节省内存并缓解多用户情况下的冲突。GetRow()带有一个参数:需要装载到数组中的记录行数。
Dim db as Database
Dim RowArray as Variant
Dim rs as Recordset
Set db=CurrentDb()
Set rs=db.opentrecordset(“Quarterly Orders”)
RowArray=rs.GetRows(rs.Recordcount)
Rs.close
…
在数组装载以后就可以对其中的数据根据情形进行操作或者把记录装载到一个非绑定的窗体中。
10.尽可能使用常数
为了让VBA取回一个变量的当前值,该变量必须是没有被引用的,这个过程每次都需要几个CPU指令;如果该变量没有在处理器的寄存器或缓存中,需要的指令更多。相反,常数只需很少的几条指令,而且还有益于增加代码的可读性。例如,可以创建一个符号常量,代替在代码中从头到尾使用42,比方说
TheAnswerToLifeTheUniverseAndEverything 并把它设定为42。VBA读取常量比变量更快。况且,其它的开发者使用常量也比42这个鬼数更容易。
11.书签的合理使用
书签是可以在用户界面里许多记录中浏览移动时使用的简便方法,但它们也是有害却引人上瘾的。说它们简便是因为它们速度快,对代码微不足道。说它们有害是因为它们只代表一个记录在一系列行中的临时位置。
要记住有两种书签:一种用于窗体,一种用于记录集。窗体书签是一个动态分配给底层记录集副本的变体数组。DAO书签是在字节数组中指向记录集中每一个记录的条目。但无论哪种书签都是随着记录集及其副本而不停地创建、破坏、重建。它们并不代表记录,与主键也没有任何关系。数据操作应该使用那些与关系数据库理论和设计相关一致的技术,而不是那些记录集中的记录的偶然位置。
12.关闭与销毁
快速的代码是整齐严谨的代码。在完成任务时要关闭记录集,在对象不再使用时要把它们设定为Nothing。不用的窗体要关闭,不用的数据库连接也要关闭。保存变量的局域化,这样在控制转换到另一个函数时它们会因超出有效范围而自动消失。宁可使用动态数组也不用静态数组。总之,要尽一切努力来消化Access应用可能消耗的资源。
Rs.close
Set db=Nothing
13.用SQL代替DAO
只有在别无选择时才在整个记录集中循环操作。优化Jet数据库以使用SQL来操作数据和数据结构。只要可能,就使用查询而不是DAO,很少有DAO比精心创建的查询速度快的情况。查询有执行规划而且可以利用索引,但DAO却不能。
如果必须用一个对象模型来选定数据,应该用ADO而不是DAO。ADO是通过对象模块来完成选定数据操作或数据定义的首选标准。DAO是凝固不变的,而且没有进一步的扩展和提高。
14.使用集合的索引数
在使用对象集合时,尽可能使用它们的索引数。索引数是集合的内部识别标记,它们比集合对象的其他属性(如名称)用起来更快。例如,下面的两个语句显示了引用当前数据库的两种不同方法。对Currentdb()的引用会自动刷新数据库的集合从而消耗时间,但第一个引用则不会。
Set db=DBEngine(0)(0)
比
Set db=Currentdb()
更快。类似地,语句
Set cntl=Forms!frmMyForm(0)
比
Set contl=Forms![frmMyForm]![myControl]
更快。
使用集合成员的索引数在循环中尤其有用,这将在下面讨论。
15.加快循环速度
当循环经过一个集合时,使用For…Each 而不是For…Next。多考虑一下窗体的控件,是这些控件组成了集合。使用下面的语法来使循环通过每一个控件:
For Each cntl on frm
….
Next
要比使用一个简单的For…Next循环运行快。For…Next循环需要重复对象引用,但是For…Each 循环不需要。
如果需要使用循环通过对象集合,开发者肯定希望避免对集合的不必要刷新。即使在一个小的数据库中,刷新集合也会破坏应用的性能。在使用For …Next循环时不必在下一行重复变量,所以可以节省时间。
For i=1 to 100
…….do what you want
Next
这样做的好处在嵌套循环中特别显著。另外,也不要重复计算For 所在行的上下限。上限应该在进入循环之前就建立好。下面的第一个代码段计算循环退出标准reccount一次。第二个代码段则在每一步循环中都计算一次。显然,第一个代码段是更快的代码。
Reccount=rs.recordcount/2
For i=1 to recount
…
Next
For i=1 to rs.recordcount/2
…..
Next
16.杜绝在代码中使用IIF()
不要在代码中使用IIF() 函数。这个函数在产生结果之前必须计算包含其中的所有表达式。标准的IF…Then..Else结构速度更快。
17.合理安排Select Case
在使用Select Case结构时,结构安排上要把经常遇到的情况放在顶端,因为在通过情况选项时要依次对每一种情况进行尝试,安排它们时把最常发生的放在前面可以使执行尽早退出这个选择结构。
18.使用.Excute,弃用RunSQL
任何时候都要避免基于Docmd的代码,Docmd是VBA最高级别的代码,是从Access没有采用VBA而只是简单的宏来完成自动操作的版本中继承来的。如果还有其他的选择,请接受吧。
Docmd.RunSql “….”
比
Querydef.Excute
运行速度慢。