级别: 初级 Tara Hall Raphael Savir 2003 年 5 月 01 日 在应用程序性能优化的 第一部分中,我们讨论了将影响应用程序性能的数据库、视图和表单属性。现在,您可能启用或禁用了某些属性并看到了某些改进。但您可以做更多的事情来提升应用程序的性能。在第二部分,我们讨论可以运行的程序代码方案。我们还测试一些通用的LotusScript方法,了解在不同的情形下哪些将以最佳性能运行。本文假设您是一位富有经验的熟悉LotusScript 的Notes/Domino应用程序开发人员。 前台/后台编程 当谈到编程时,我们简单的区别有时也称为的前台程序和后台程序。前台程序是从应用程序的用户界面(UI)运行的程序,例如,从操作菜单手动运行一项代理。这类程序的优势在于易于诊断,因为您可以通过手工测试很容易地确定程序运行良好和低效率运行。前台程序的性能问题经常与字段、按钮、代理相关-某些您可以更改的UI元素。正如在第一篇文章中建议的,一个良好的测试环境可以帮助您隔离这类故障。 后台程序是在后台运行的程序。这包括预定的代理,它不时成为与系统性能相关的故障的来源。例如,您可能拥有一个清除数据库保存/复制冲突的预定的代理,您可能发现该代理在不正常的时间范围内完成其任务,或者它消耗大量紊乱的系统资源来完成这一项任务。要测试后台程序,审视您的日志是否异常,如完成一项任务的长时间流逝。如果您正在测试的后台程序是代理,检查代理日志,查看代理是如何很好地完成其任务的。 现在,我们区分了前台程序和后台程序,那么我们讨论一些影响这两者性能的常见程序错误。
<shape id="_x0000_i1027" style="WIDTH: 0.75pt; HEIGHT: 0.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.ibm.com/i/c.gif" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image004.gif"></imagedata></shape>
|
临时变量 编程时开发人员最容易犯的一个错误是不能使用临时变量作为检索昂贵的数据的占位符。最明显的一个例子是依靠@DbLookup 公式结果的程序。如果您的程序使用要查找多次的数据,那么将该数据设为局部变量。现在您可以根据需要多次使用这一数据,包括:
- 检查错误条件时
- 将数据分解成更小的单元时(例如,多值列表)
- 对数据进行排序时
另一个典型例子是拥有大量数据和用户的文档,用户可以通过点击按钮,以不同的方式对数据进行排序。这种功能旨在模似悬浮的视图排序功能,但发生在文档的大表格内部。很明显,这是一个将您的大量数据设为局部变量,然后对局部变量进行排序的恰如其分的环境。它带来的性能方面的差异令人惊讶。在作者过去需要花费一分多钟时间来运行的程序通过局部变量的使用降低到一秒内。 最后,第三个例子是查找数据库中特定名称的视图的程序。您可能被通过db.views 属性进行循环所吸引,但您可以通过第一次设定局部变量,如 viewLIST = db.views 来缩短程序运行时间,然后您可以反复使用该临时变量以实现最佳的性能。
计算字段 限制文档中计算的次数可以提升性能。文档中计算执行的次数越多,程序运行的速度就越慢。无论什么时候您以读模式打开一份文件,系统要进行一些计算。当您以编辑模式打开一份文件,或从读模式切换到编辑模式时,系统要进行其它计算。用户应该了解以读模式打开文件和以编辑模式打开文件所用时间的比例,从而确定要减少的字段/计算。以下介绍每种情况的一些例子:
@If(@IsDocBeingEdited; @DbColumn("Notes"; ""; ViewName; 1); kList) |
在这种情况下,确保您阻止执行的任何程序(如前面所述)在切换到编辑模式之后开始执行。例如,当用户以读模式打开文件时使用 @DbLookup 或 @DbColumn 公式的关键性字段为防止运行的首要候选对象。但如果用户将文件切换到编辑模式,使用 postModeChange 事件强迫文件刷新(例如, if source.editmode then call source.refresh )。此外,选择关键性字段选项"文件刷新选项。" 在选定该选项之后,当用户从读模式切换到编辑模式时,文件自动刷新一次并强迫关键性字段重新求值。 <shape id="_x0000_i1028" style="WIDTH: 242.25pt; HEIGHT: 235.5pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www-128.ibm.com/developerworks/cn/lotus/ls-appper/part2/images/image004.jpg" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image005.jpg"></imagedata></shape>
在这种情形下,您可以希望尽可能多的把昂贵(性能方面)的程序转移到按钮中,从而频繁的编辑不会陷入困境。这假设即使在编辑文件时,大多数用户不需要更改所有关键性字段。 您可能认为上述建议需要更多的计算,而不是少数计算。从某种意义上讲,这是对的。只有采用这些步骤才能避免昂贵的计算,如@Db 公式,同时不用括号把简单的 @properCase 的括起来,例如使用 @If(@IsDocBeingEdited) 。它不值得做。 刷新字段值 通过选择表格属性对话框表格信息标记上的自动刷新字段选项,您可以设置字段值为自动刷新。 <shape id="_x0000_i1029" style="WIDTH: 286.5pt; HEIGHT: 311.25pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www-128.ibm.com/developerworks/cn/lotus/ls-appper/part2/images/image006.jpg" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image006.jpg"></imagedata></shape> 这样做会对您的性能产生负面影响,因为每次用户把鼠标移到表格字段时所有以前的字段都重新计算。这一繁重计算的目的是首先检查Input Translation和Input Validation公式,但实际上所有程序都运行。 当用户选择特定值时,如果您需要刷新计算的字段中的关键字表,选择字段属性对话框控制标记上的"当关键字改变时刷新域"选项。例如,假设您在表格中有多个关键字字段,关键字字段二、三和四的值不同,取决于用户在关键字字段一中选择的值。在这种情况下,使用"当关键字改变时刷新域"功能。这就像按下F9键一样,只是每次这一关键字字段中的值更改后它自动运行。这提供了胜过表单对话框中"自动刷新域"选项的性能,因为文档只在第一个关键字字段中的值更改后才刷新,而不是任何值更改后都刷新。注:您必须为其它关键字字段设置字段选项"当文档刷新时刷新选择"。任何无需参与这一动态关系的关键字字段无需设置这一项功能,因此当第一个关键字字段的值更改后它们无需刷新。 <shape id="_x0000_i1030" style="WIDTH: 279pt; HEIGHT: 269.25pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www-128.ibm.com/developerworks/cn/lotus/ls-appper/part2/images/image007.jpg" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image007.jpg"></imagedata></shape> 使用"创建时计算"的域类型 当用户创建文档时创建时计算计算字段的值。您可以使用创建时计算来延续这些值,或者如果某些其它程序将设置一个字段,但您希望它保留原值。例如,响应文件中名为OriginalSubject的字段包含公式Subject。如果用户创建响应文件,该字段沿袭选定的主文件,再也无需计算。另一个例子是称为DateClosed的字段,它由运行操作条上按钮的程序代码。由于从未想过这一字段更改自己的值,我们将其设为创建时计算并使用公式DateClosed。这使其可以做为占位符公式来运行。它只在第一次计算时才尝试计算(在这种情况下,我们假设无沿袭值在使用),此后只采用强行输入的值。注: 只要用户保存了文件,创建时计算的域向输入到其中的值应用正确的数据类型。 您可能会问,在这两个例子中使用创建时计算的域 和计算域 有什么区别。主要的区别很简单,每次编辑、刷新和保存文件时计算域都计算,即使它没有真正的工作要执行也是如此。如果有大量与上述一样简单的公式,那么这一字段类型会给您的应用程序的性能带来稍许差异。但是,如果在您的表单中有许多类似的字段,您将看到性能方面的差异。在此例中,由于设置这一字段为计算字段不会带来任何优势,您的用户可以获得更好的性能。一个真正不劳而获的例子!
缓存和非缓存参数 缓存和非缓存参数适用于所有@Db公式。如果您规定了缓存参数,公式值将被保存到缓存中以便于检索。如果您规定了非缓存参数,公式值将不被保存到缓存中,因此每次查找都基于数据库来进行。开发人员经常超额使用非缓存参数并且更多的资源用于从数据库检索数据而不是从缓存。不要对您认为重要的数据使用非缓存参数。 用户反而考虑数据更改的程度:数据更改得越频繁,您就越想使用非缓存参数。对于不频繁更改的数据,使用缓存参数。例如,假设您有一个讨论数据库,其中用户可以使用规定的关键字,它们创建了新类别。(也就是每次用户创建新主题时,他或她可以为该主题规定任何类别。)在这种情况下,这类数据可能相对不重要,但您仍然需要使用非缓存参数,从而在一行中输入两个或三个主题的用户发现新类别在下一主题的关键字字段中立即反映出。为了提高性能,使用非缓存参数和ODBC访问:"在索引中产生唯一的关键字"选项,它已经在 第一部分中讨论过。记住:"在索引中产生唯一的关键字"选项只列出唯一的类别来维护一个较小规模的视图索引。 <shape id="_x0000_i1031" style="WIDTH: 269.25pt; HEIGHT: 204pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www-128.ibm.com/developerworks/cn/lotus/ls-appper/part2/images/image009.jpg" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image008.jpg"></imagedata></shape> 举一个反例,假设您查找薪水信息。这是一类至关重要的信息,但是,通常每隔几个月薪水才会更改一次,从而使这类数据成为缓存的一个很好的候选对象。
LotusScript方法 Lotus测试来确定在获得一组文档方面,谁是表现最好的最常使用的LotusScript 方法-实际上在LotusScrip任何部分程序代码中最常运行的任务。在这一小节,我们比较以下常用的LotusScript方法:
- db.FTSearch
- db.Search
- view.GetAllDocumentsByKey
- view.GetDocumentByKey
在这类测试过程中,使用不同大小的数据库(10,000、100,000和1,000,000份文档)来了解每种方法是如何很好地运行的。 db.FTSearch方法 在对数据库的全文检索后,db.FTSearch返回文档集合。它运行良好,但需要当前的全文索引,也许对语法更深入的了解。此外,根据服务器的Notes.ini 设置,对返回的文件集合的大小施加了限制。当然,如果您的查找是基于多文本字段的内容,那么这是您唯一切实可行的选择。 db.Search方法 在使用视图选择公式进行数据库查找之后,db.Search返回文档集合。对于大数据库中的小规模集合来说这是相对低效率的执行程序。例如, 如果您的数据库中有100,000份文档并且您只需查找5或10份文档,您可能希望避免使用db.Search。在另一方面,它不需要全文索引和预先创建的视图,因此它是一种非常方便的查询方法。例如,如果您对几乎不能控制的数据库进行查询,这可能是您唯一可靠的选择。 view.GetAllDocumentsByKey方法 从Release 5开始,这种方法成为检索文件集合最快的方式。唯一的缺点是需要建立相关的视图。但是,只要您精简了您的视图设计和不使用昂贵的时间/日期敏感的公式(正如第一部分所讨论),这些视图对性能和磁盘空间的影响应可以降低以最小,程序使用view.GetAllDocumentsByKey从这些视图获得文件集合的速度将非常迅速。
set doc = DocumentCollection.GetNextDocument ( doc ) |
其中i从1增加到DocumentCollection.count。 对于文档小集合来说-和对于单独运行的程序来说,如预定的代理-性能下降为最小,但对于文档大集合来说-或者许多用户同时运行的程序来说会影响性能,它使GetNth成为不明智的选择。GetNth方法通常适用于您想要从集合中挑选文档的情形,而不是简单地遍历整个集合。 view.GetDocumentByKey方法 这是唯一一种不将一组文档保存到内存中的方法。view.GetDocumentByKey而是使用已经构建的视图索引作为其集合并且一次只把一份文档放到视图中。这种方法与view.AutoUpdate = False一同使用,它非常迅速且不需要内存来保存可能的大文件集合。 注:如果前一份文档已经从视图中删除,当有机会访问视图中的下一文档时,view.AutoUpdate = False主要用于避免错误信息,但它还可以显著提升性能以便运行代理。当更改文档中的数据时,使用view.AutoUpdate = False您会看到视图中有显著的改进。
事件、共享的要素和其它 以下是必须记住的一些编程注意事项:
当删除程序时,注意完全删除它。不要只是重新标记它为删除,或者部分删除程序。您可以根据circle/squiggle是填满还是清空来告诉事件是否有程序代码。
- 共享的要素是低效率的执行程序,但是它们可以在多个位置使用,从而弥补了其糟糕的性能。
使用共享的元素来保存某些工作以及重复一个要素来提升性能时仔细考虑。
在精心编程的情形下,通过当它逻辑上应结束时使其继续运行,这可以确保您的程序不会"漏掉"。
大规模的子表单会影响应用程序的性能。如果您在应用程序中未多次使用大规模的子表单,考虑在每个表单中重复这类字段,而不是使用子表单。
在文档中使用较少的字段与性能相关,而不是文档的大小。使用具有较多数据的较少字段,如多值字段,而不是使用较少数据的比较多的字段可以提升应用程序的性能。由于许多传统的编程人员对Notes/Domino应用程序开发不熟悉,这可能一些概念直观,但实际测试很明显地验证了这一概念。
- 使用view.Autoupdate=False 来阻止视图刷新。
正如前面介绍,同时使用 view.GetDocumentByKey 方法和这一属性可以是高效率的执行程序。
当您需要使用静态值来标记大量文档时这种方法极其有效,如当前日期/时间或值的标记集。
- ForAll 语句是遍历循环的最快方法。
- 固定数组是比动态数组更卓越的执行性能。
动态数组是比固定数组稍微低效率的执行性能,但动态数组的规模恰如其分,在您选择固定还是动态数组之前请预以权衡。
<shape id="_x0000_i1032" style="WIDTH: 0.75pt; HEIGHT: 0.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.ibm.com/i/c.gif" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image004.gif"></imagedata></shape>
|
结语 我们希望这些注意事项对您有所帮助,在实施这些方案之后您将会很快看到应用程序性能方面的改进。我们希望能够聆听到您的应用程序性能调整的最佳方案,因此如果您有任何好的建议并且希望与广大的Notes/Domino应用程序开发人员共享,请提交给我们。
作者简介
<shape id="_x0000_i1033" style="WIDTH: 0.75pt; HEIGHT: 0.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.ibm.com/i/c.gif" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image004.gif"></imagedata></shape> |
|
<shape id="_x0000_i1034" style="WIDTH: 3pt; HEIGHT: 3.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.ibm.com/i/c.gif" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image001.png"></imagedata></shape> |
Tara Hall has authored this article |
<shape id="_x0000_i1035" style="WIDTH: 49.5pt; HEIGHT: 3.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.ibm.com/i/c.gif" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image001.png"></imagedata></shape> |
|
<shape id="_x0000_i1036" style="WIDTH: 3pt; HEIGHT: 3.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.ibm.com/i/c.gif" src="file:///C:/DOCUME~1/user/LOCALS~1/Temp/msoclip1/03/clip_image001.png"></imagedata></shape> |
Raphael Savir has authored this article |
|