如何优化lotus script语句
1. 前言
写这个文档的起因是我在使用一段程序代码的时候发现执行速度不满意,100条notes文档处理起来需要64秒钟。虽然这段代码的复杂程度很高,但是运算量不大,最多执行190个循环。所以我试着修改这段程序,最终将运行时间降低到5秒以下。这非常令人惊喜的结果!10倍的速度啊!
1.2. 什么是运行速度的瓶颈?
根据人们通常认为运行速度的敌人有以下几个:
> DBSearch(全文检索)。
> 多数据库操作。
> 巨大的数据库(超过10000条文档记录,容量超过100M)。
上面三个问题,人们可以根据经验认同和接受,所以我就不在多论述。
1.3. 什么限制了Lotus Script程序的运行速度?
Lotus Script是和Visual Basic 相似的一种脚本语言,从脚本语言本身来讲,运行速度比不上编译语言,这是公认的。
但是我们在编写Lotus
1. 前言
写这个文档的起因是我在使用一段程序代码的时候发现执行速度不满意,100条notes文档处理起来需要64秒钟。虽然这段代码的复杂程度很高,但是运算量不大,最多执行190个循环。所以我试着修改这段程序,最终将运行时间降低到5秒以下。这非常令人惊喜的结果!10倍的速度啊!
1.2. 什么是运行速度的瓶颈?
根据人们通常认为运行速度的敌人有以下几个:
> DBSearch(全文检索)。
> 多数据库操作。
> 巨大的数据库(超过10000条文档记录,容量超过100M)。
上面三个问题,人们可以根据经验认同和接受,所以我就不在多论述。
1.3. 什么限制了Lotus Script程序的运行速度?
Lotus Script是和Visual Basic 相似的一种脚本语言,从脚本语言本身来讲,运行速度比不上编译语言,这是公认的。
但是我们在编写Lotus Script程序时,同样会发现我们代码好象已经写的不能在优化了,速度还是不如意。这是为什么呢?下面在我的实验中,你就会发现其中的原因。
1.4. 我的实验
1.4.1. 实验环境及其他描述
这个实验是我根据实际情况改变了一些,但不至于影响我的论述。
运行环境:
Domino 5.0.7(中文) ,Notes 5.0.4(中文)
Windows2000 Advance Server
HP LH3000 (PIII750、Memery 500M)
实验的功能:
从服务器上指定的应用数据库App.nsf中读取文档,分析其中的数据后,把分析结果写到本地数据库中。一个文档可以对应多个分析结果文档。分析过程中要读取另外三个数据库:配置库Config.nsf,组织库Organize.nsf,应用配置库Process.nsf。实验一共涉及5个数据库,这正符合多数据库操作的特点,每个库的总文档数不超过500个,大小在30M以下。
Lotus Script代理MyAgent,运行在本地数据库,视图操作(@ToolsRunMacro)。引用四个Script Liberary: LibA,LibB,LibC,LibD,每个库都分别定义了一个类(Class)。四个类分别对应上面描述的5个中的4个数据库(除了本地库)。
MyAgent运行处理App.nsf中的46个文档,在本地创建95个文档,优化前运行时间是64秒。
1.4.2. 实验过程
1.4.2.1. 空间换时间
最常见的方法,用内存空间换取时间,我把代理中能够放到全局变量的变量都声明为全局的。
结果,失败,几乎没起什么作用,还是64秒。
然后在我在一段循环代码中发现有两行:
Forall x in myvariant
Set ObjA = New ClassA()
Set ObjB = New ClassB()
………
Set ObjA = Nothing ‘ Obj A is ClassA Object declare in LibA
Set ObjB = Nothing ‘ Obj B is ClassB Object declare in LibB
End Forall
注释掉Set = nothing 的两行。(空间换取时间嘛)。
哗!有变化了,时间缩短到了44秒。
但是这仍然无法令人满意。
1.4.2.2. 迷茫
MyAgent程序代码已经不能再做什么手脚了。还没有什么起色。
我把目标转移到了那几个Script Liberary中。这四个库是完全按照面向对象的来设计的。如果要修改除非是重新设计类结构。可是我知道类结构的设计是合理的(为什么?要是不合理我为什么用它?),所还只能从代码入手。
于是我又采用时间空间换时间的做法,对类中的变量进行了全局定义,尽管我明白这不会起什么作用。因为变量是在For循环中new,类的变量全局否就没有什么关系嘛。(Notes的类有些特殊,不能声明C++中类似Static类型的变量)。
果然时间仍是44秒。我密茫了。
1.4.2.3. 光明
在你最失望的时候,你将会做什么?
我会再搏一次。
看来类结构不得不变了。先让我们看一下类是如何声明的。
Class ClassA
Doc As NotesDocument
Vw As NotesView
…….
Sub New(myObjD as ClassD)
…….
Vw = myObjD.getView(“vwA”)
Set doc = Vw.getDocumentBykey(key)
……
End Sub
……..
End Class
请注意,为了清晰,我只列出了最后修改的代码,实践证明问题就是出在这里。我们知道,ClassD是一个继承NotesDatabase的类。我已经在代理MyAgent中把myObjD 定义为全局的了。
我把Vw声明为ClassD的属性,然后在ClassD增加了Public方法,GetDocumentBykey(),于是代码变为
Class ClassA
Doc As NotesDocument
‘Vw As NotesView
…….
Sub New(myObjD as ClassD)
…….
‘ Vw = myObjD.getView(“vwA”)
‘ Set doc = Vw.getDocumentBykey(key)
Set doc = myObjD.GetDocumentByKey(key)
……
End Sub
……..
End Class
再次运行,25秒!我仿佛在黑夜里见到了黎明的曙光!
我如法炮制,修改了另外的几个类,随后使时间缩短在5秒以下。
从64秒到5秒!10倍多的速度啊!
1.4.2.4. 实验总结
哦,都深夜啦,该睡觉啦,明天在整理总结吧。
1.5. 你的代码需要优化吗?
作过一些SQL的都知道要避免在循环中查询数据库。我们在Lotus Script中需要注意这一点吗?当然。但这不是最重要的。
在循环外部一下子得到了一个结果集(NotesDocumentCollection),可是NotesDocumentCollection的遍历方式和NotesView一样,速度上也强不到哪里去(NotesDocumentCollection和NotesView的速度,本人认为NotesView要略胜一筹)。所以这不是主要的。
重要的是什么呢?是不要在循环中反复openview(GetView)。正象在实验中的表现一样。在循环中new一次,就getView一次。
通常如果你的代码是面向过程的,你基本上不会遇到这个问题,可是如果你要是设计了一个面向对象的程序代码呢?
—–