这份白皮书阐述对 IBM Lotus Notes 和 Domino 应用程序的性能形成巨大影响的最重要因素。它的主要目的是帮助 Notes 客户端应用程序开发人员识别问题,而后针对问题提供解决方案,从而实现最佳的性能。
在这里,假设您已经知道如何建立 Notes 设计元素,以及知道如何对表单、字段、视图和列等组件设置选项。这份白皮书为各个级别的开发人员提供了学习材料。
在 Lotus Notes 中开发简单的应用程序很是容易,而且在用户和文档的数量不多时,通常不会遇到性能问题。然而,只要应用程序是成功的,用户和数据的数量就会逐渐增多。若是在设计时没有考虑到性能问题,那么您的应用程序此时将会变得异常缓慢。
这份白皮书讨论影响 Notes/Domino® 应用程序的性能的主要因素,而且解释开发人员如何才能得到最佳的性能。这并非一份详尽的指南;相反,咱们主要关注最多见、最严重的设计问题。
这份白皮书的主要目的是帮助您识别 Notes 客户端应用程序的问题,并指导您找到解决办法。Web 应用程序也存在相似的设计问题,但它们的问题主要在另外两篇文章中解答,即 Appendices Group C of the IBM Redbooks 出版物 Performance Considerations
for Domino Applications 和 IBM Business Partner 文档 Performance Engineering Notes/
Domino Applications。
通常而言,如下因素对应用程序的性能影响最大:
- 视图的数量及其复杂性。删除不使用的视图或合并类似的视图。对于包含相同文档但使用不一样排序的视图,使用一个可从新排序的列合并它们。删除不须要的列,并简化选择和视图列公式。检查是否存在您不能访问的“服务器私有”视图或其余视图。
- 在视图选择公式或列选择公式中使用 _cnnew1@Today 和 @Now。尽可能避免这种状况。参见 IBM Support Web 站点技术文档 Time/Date views in Notes: What are the
options?;并阅读本文下面的视图小节。
- 文档数量。文档越多打开的速度就越慢。能够考虑压缩旧文档或将主文档合并为单一文档。例如,若是您的主文档是一个“订单”,那么将订单上的每一个“排列项”放到独立的文档中就是一个糟糕的作法。Lotus Notes 不是关系数据库,而是面向文档的数据库。
- 储存在文档中的摘要字段的数量。不属于富文本的字段称为“摘要”字段(尽管这个称呼过于简单化)。文档包含的摘要字段越多,将其编入到视图索引中所需的时间就越长(若是存在几百个字段,那么所需的时间将增长 30%)。只要字段存在,即便不在视图中使用它们,也会形成同样的结果。有时使用更少的文档却须要更多的字段,反之亦然;必须仔细考虑才能为提高性能作出正确的选择。
- 表单的复杂性。尝试将表单的数量限制为与实际须要的字段相等。表单越长,打开、刷新和保存它们所需的时间就会大大延长(而且视图索引器须要处理的字段也会增多)。
- 修改文档。对文档进行没必要要的修改会增长索引器的负担,从而下降了视图索引的速度,而且还会影响复制和全文本索引的速度。
- 删除文档的数量。当删除一个文档时,就会留下一个称为“删除存根”的标记。复制程序须要根据这个标记决定是否从其余副本中删除相同的文档,或将“缺失”的文档复制到该副本。删除存根最终会过时(默认为 90 至 120 天),所以只要数据库保持正常的删除文档数量,就不会形成问题。
然而,咱们见过一些应用程序包含的删除存根要比文档多好几倍。若是使用代理程序在夜间执行文档删除,而后从其余外部数据源建立新的文档,那么一般会出现这种状况。不要使用这种方法。您可使用更高级的算法比较文档和源数据,从而肯定应该更新或删除哪些文档。参见 Lotus Sandbox download 了解更多信息。
- Reader 字段。若是有必要使用 Reader 字段,那么必须使用它 —— 没有其余方法可以提供它所提供的安全性。但要注意它对视图的性能形成的影响,尤为是用户仅访问大量文档中的一小部分文档时。这份白皮书的视图小节讲述了一些减少该字段的影响的技巧,另外 developerWorks 文章 Lotus Notes/Domino 7 application performance: Part 2: Optimizing database views 也讨论了相似的主题。
- 用户数量。若是服务器上存在大量用户,那么将会影响应用程序和服务器的性能。当应用程序的性能已经处于临界状态时,添加新的用户会致使性能恶化。改良设计会有所帮助,但您还须要在其余服务器上建立副本(尤为是集群服务器),或鼓励用户建立更 快的本地副本。
参考 Domino Designer 帮助文档“Properties that improve database performance”的数据库选项列表,您能够利用它调试性能。在不少状况下,这些选项经过削弱性能来得到其余功能;所以,对于特定应用程序不须要的功能,能够禁用它。
对性能有巨大影响的选项包括:
- Don't maintain unread marks。
- Don't maintain the "Accessed (In this file)" document property。若是“不进行维护”,您就不知道最后一次读取文档的时间。对长时间不读取的文档进行归档时,这个信息很是有帮助。
- Disable specialized response hierarchy information。若是禁用该项选,就不能使用 NotesDocument.Responses 属性,也不能使用 @AllDescendants 或 @AllResponses,它们偶尔用于视图选择公式和复制公式。
- Disable transaction logging。这个选项对性能的影响取决于管理员如何在服务器上设置它,以及用户的数量。若是用户不少,使用事务日志能获得更佳的性能。尝试启用和禁用该选项形成的影响。事务日志用于恢复。
- Optimize Document Table Map。若是应用程序包含的各类类型的文档大体相等,而且大多数视图仅显示一个类型(例如,SELECT Form = “xyz” & ...),这个选项就很是有用。若是视图选择公式都采用这种方式,而且先对表单进行检查,那么视图索引就会变快,由于这能当即排除不使用该表单的文档。
使用 NSFDB2(在 DB2® 数据库中存储 Domino 数据)并不能提高性能,事实上,使用传统的 NSF 文件还会更快一些。NSFDB2 的目标是添加功能,而不是提高性能。
全文本索引可能会占据大量的磁盘空间,但这一般是物有所值的。您能够利用全文本索引在代理中执行更快速的搜索,若是没有这个索引,用户必须使用更慢的搜索方法,这将致使长时间占用服务器,从而形成性能降低。
注意:在 8.0 版本的 Notes 中,一个新数据库属性使您能够关闭非全文本索引数据库的“全文本”搜索。通常而言,即便您拥有全文本索引,该选项也是颇有用的;它确保索引被意外删除以后,用户会看到一条消息,而不只是以为性能平白无故忽然降低。
对于数据库,除了属性对话框以外,您还能够设置的另外一个地方是 ACL 对话框。限制用户建立视图和文件夹可以减小服务器的负载(见图 1)。
若是您取消选择“Create personal folders/views”,用户仍然可以建立私有视图,但建立的视图必须储存在本地的桌面文件中,而不是存储在服务器上。所以不会对应用程序的性能形成太大的影响。
桌面私有视图确定会对性能形成影响,由于索引它们时用户必须从服务器实时提取数据。所以过多地使用桌面私有视图还会使服务器陷入困境。因此要避免为启用“Private on first use”选项的用户自动建立我的视图。(下面会对此进行详细阐述)。
大部分 @ 函数都是至关快的,但有一小部分比较慢。所以要谨慎地使用它们:
- @Contains 的开销还不是十分大,一般用于测试列表是否包含某个值,这是一种低效的方法。例如,若是 Cities 包含值“East Lansing”,则表达式 @Contains(Cities; “Lansing”) 返回 True。若是这正是您须要的,固然很好;但若是您查找的是包含“Lansing”值的条目,那么应该使用 =、*= 或 @IsMember。这些函数更加快,由于若是第一个字符不匹配,它们就再也不扫描整个字符串。
- @For 和 @While 一般能够被更高效的 @Transform 代替,或被其余对整个列表进行一次性操做的函数代替。
- @Unique 必须将列表中的每一个值与其余值进行比较,所以执行时间与列表中的项数的平方成正比。对于其中的各个值都具备唯一性的列表,这个函数的表现会更好。后面还将对此进行讨论。
- @NameLookup 相似于 @DbLookup,但它仅用于目录信息。
- @DbLookup 和 @DbColumn。过分使用和错误使用这些函数是形成表单延迟的主要缘由。下面将对此进行详细讨论。
咱们一般没必要要地使用了宏语言中的循环函数。
尽管没有在这个
Domino
Designer 帮助文档中阐述宏函数,但几乎全部接受字符串参数的宏函数均可以对列表进行操做。例如,@Left(x; “,”),其中
x 是一个列表,它返回一个全部元素都被“左置”的列表。
注意:在之前,
@UserRoles 和
@UserNamesList 函数都会形成严重的性能问题,但从 Lotus Notes 6.0 开始,这些函数的结果都将被缓存。
影响 @DbLookup 和 @DbColumn 的性能的 3 个主要因素是:
使用缓存
许多开发人员过分地使用“NoCache”选项,尤为是在关键字公式中。这种现象很容易观察到,由于在开发和首次测试期间须要常常编辑关键字,所以NoCache(不使用缓存)是“正确的选择”。
而后,在应用程序投入使用以后,就不会常常编辑关键词。在出现新值时,迟一些再提供给用户能够获得更好的性能,这种代价是能够接受的。务必在必要时才使用“NoCache”选项。
有 3 个缓存选项:
- “Cache”(默认)仅对在应用程序会话期间对视图的首次查询起做用,它会记住该查找结果供之后使用,直到您退出应用程序。
- “NoCache”绕过缓存直接指向视图。若是存在同一查找的缓存值,将不更新缓存。
- “ReCache”是一个容易忽略的选项,它一般直接指向视图,但它也使用查找值更新缓存。经过使用 ReCache,您能够在特定时间更新缓存,好比在保存查找所引用的文档时。在其余时候也可使用缓存值,由于您知道对于用户输入的信息而言,这个值至少是最新的。
为查找选择正确的视图
有时对 @Db 函数最高效的视图并非最好的。例如,@U nique(@DbColumn(“”:“NoCache”; “”:“”; “InvoicesByCompany”; 1)) 存在几个问题:
- 它在这里不该该使用 NoCache。您并非天天都添加一个公司,即便添加,也能够在 Invoice 表单的 Postsave 中使用“ReCache”选项,让新添加的名字当即可用。
- 当前的数据库是用表达式 “”:“” 指定的。相反,应该使用 “”,由于 “”:“” 不只带有更多容易混淆的标点,并且它的计算速度也要慢一些。
- 不要查找带有重复值的列表,而后再使用 @Unique 删除重复内容。相反,您应该查找其值具备唯一性的视图列,由于它们来自一个已分类的列。
最后一点特别重要,由于使用 100 个测试数据文档时可以很好工做的列查找,在实际使用中性能就会急剧降低,所以此时应用程序面对的是数千个文档。尤为是在服务器上使用该应用程序时,须要经过网络将视图列的完整内容发送给用户工做站,这是须要时间的。从视图读取已经存在的唯一值要快得多。
注意:在获取唯一值列表时,彷佛可使用“Generate unique keys in index”选项代替已分类的列,但实际上它存在一些缺点,所以不适合该用途。
查找须要花很长时间索引的视图也是不明智的,尤为是在选择公式或列公式中使用@Today 或 @Now 的视图。若是您仅需查找特定日期的文档,那么能够对仅包含这些文档的视图使用 @DbColumn,对包含全部按日期排序的文档的视图使用 @DbLookup,并提供日期做为查找键。
避免重复查找
没必要要地使用 @Db 函数的方式有好几种。这里给出一些常见的方式:
在公式中重复
@If(@IsError(@DbLookup(“”: “NoCache”; “”; “SomeView”; CustID; 3); “”
@DbLooku p(“”: “NoCache”; “”; “SomeView”; CustI D; 3))
|
这个公式不只使用了不须要的 NoCache,而且进行了两次查找(实际上一次查找就能够了)。下面是两个修改后的公式:
_tmp := @DbLookup(“”; “”; “SomeView”; CustID; 3); @If(@IsError(_tmp); “”; _tmp)
|
或
@DbLookup(“”; “”; “SomeView”; CustID; 3; [FailSilent])
|
在读模式中使用没必要要的关键字查找
当打开文档进行查看时,对于某些类型的关键字字段,Notes 客户端不须要知道选择列表。但复选框和单选按钮字段除外,在其中甚至以读模式显示全部选项,而且全部使用关键字的内容都是同义词(“Display text|value”),由于文档仅储存“value”,而表单必须显示“Display text”。
可是在其余状况中,须要编写该关键字公式来延迟查找,直到您实际须要选择列表为止:
_t := @If(@IsDocBeingEdited; @DbColumn(""; ""; "Customers"; 1); @Return(@Unavailable));
@If(@IsError(_t); ""; _t)
|
经过在文档的读模式下返回 @Unavailable,公式会再次通知表单,让它询问随后是否须要选择列表。这将在用户切换到编辑模式而且指针点击该字段时发生。
所以,在用户仅查看文档时,您不只要避免进行查找,而且要分散编辑文档时的延迟;8 个半秒延迟确定没有一个 4 秒延迟那么烦人。若是用户的指针没有指向该字段,那么他们根本不须要进行查找。
在只需一个查找的位置使用多个查找
假设您将一个客户 ID 储存在“invoice”文档中,并想经过这个 ID 查找和显示客户的名称、地址和购买联系人姓名。这样,表单上就有几个 Computed for Display 字段,每一个字段包含一个使用 @DbLookup(“”; “”; “CompanyByID”; CustID;
x) 的公式,其中
x 是列号或字段名。
使用一个列来包含您须要的全部值会更高效,您能够从中找出每一个字段值。所以这个列公式应该为:
CustName : StreetAddress : (City + “ ” + State + “ ” + Zip) : PurchasingContact
|
在您的表单上,添加一个隐藏的 Computed for Display 字段,名为 CustDetails,以下所示:
@DbLookup(“”; “”; “CompanyByID”; CustID; 4)
|
(假设合并的列为列 4)。而后,您就能够在须要显示名称的地方使用公式:
在刷新时重复查找
假设您在组建表单时须要在计算字段中查找客户的经理的名字,以下所示:
@DbLookup(“”; “VOLE 1”: “EmpData. nsf”; “EmpByName”; @Name([CN]; @Username); “Manager”)
|
每次刷新表单时,都从新计算已计算的字段。许多表单须要常常刷新(由于您启用根据关键字字段的变化刷新字段的选项),所以这会严重影响速度。将字段设置为“Computed when Composed”会更好。
若是不须要将字段储存在文档中(记住,不要储存不须要存储的字段!),而后对它使用Computed for Display,但这个例子中,须要按照如下步骤避免在刷新时重复查找:
@If(@IsDocBeingLoaded;
@DbLookup(“”; “VOLE 1”: “EmpData. nsf”; “EmpByName”; @Name([CN]; @Username); “Manager”);
@ThisValue)
|
使用 @DbColumn 分配序列号
这是一个常常犯的错误。当设计人员必须为每一个文档建立一个唯一的 ID 时,他们一般向最新的现有文档的编号加“1”。所以他们的公式以下所示:
tmp := @DbColumn(“”:“NoCache”; “”; “RequestsByNumber”; 1);
nextNumber := @If(tmp = “”;
1;
@ToNumber(@Subset(tmp; -1)) + 1);
@Right(“000000” + @Text(nextNumber); 7)
|
这是一个很是糟糕的主意。随着文档数量的增加,@DbColumn 的执行时间会愈来愈长。此外,当应用程序有多个用户时,它不能保证 ID 是唯一的,尤为是存在多个副本时。
若是在文档保存以后再给它分配序列号,那么序列号在此以前是不可用的,这很不方便。不过,若是在建立文档时就给它分配序列号,这将留有充足的时间让其余人使用相同的序列号建立并保存文档。
您可能须要从新考虑本身的需求。有时应用程序实际上仅须要唯一的非数字
标识符,而咱们却老是要求使用序列号。仔细查看 @Unique 函数,它生成一个很短但基本上是唯一的值(经过一些额外的工做就能够保证唯一性,例如为每位用户添加一个唯一的“前缀”,一般是他们的名称的首字母)。
在这个小节中,咱们将解决一下值得关注的问题。
由于存储字段通常都会使应用程序变慢,因此若是可以在须要时轻松地计算这些值,就应该避免存储值。这里有一个折中;当文档以读模式打开时,不会计算 Computed 字段,所以若是它是一个很慢的公式,则最好储存值,这样可以改善读模式的性能(另外一方面,这还意味着它会过时)。
但必定不要使用 Computed 字段从新显示另外一个字段的值 —— 这样会存储相同信息的两个副本。
在一个表单中使用大量字段的最多见缘由是,一个表有多个行和列的信息,而且每一个单元格有一个字段,超出了支持的行数。这是一种棘手的状况,由于到目前为止使用表单是最简单的办法。
不过,还有其余办法能够管理表的值。最多见的办法是将表放到一个富文本字段中,而后让用户根据须要进行填充(在富文本字段的默认公式中使用 @GetProfileField 从配置文件文档读取一个“starter”表)。这样作的缺点是用户在填写表格时不能得到帮助,要是存在私有字段的话,就能够提供关键字列表、转换和验证。不过,有时这也是一种可接受的办法。
如今已经发布一些工具和技术,能够在对话框中每次仅编辑表的一行,而后在表中显示结果。例如,Lotus Sandbox 中的 Domino Design Library Examples 包含一组设计元素,可用于在表中编辑和显示数据,而不要求每一个单元格必须有一个字段。在名为“Table Editor”的数据库文档中,将详细描述这个系统。须要付诸必定的努力才能实现它,但它对性能很是有帮助。
有时,咱们在大部分文档中能够看到包含许多空字段的表单。例如,大约 5% 的文档须要一个包含 50 个字段的“Regulatory Approval”部分。而其他 95% 的文档则存储了这些空字段,这不只浪费空间,并且还形成糟糕的性能
对于这种状况,使用两个不一样的表单可能更好 —— 一个包含必需字段的主表单,和一个分开的“Regulatory Approval”表单,它多是对原始文档的响应,或者仅在须要时建立。在这里,能够经过使用额外的文档来避免使用更多的字段。
不要忘记多值字段。除了经过 5 个字段让用户输入 5 个不一样的值以外,还可使用一个能够输入多个值的字段。对条目的数量没有任何限制(除非您选择必须使用一个),而且生成的值在视图和公式中
更容易 使用。
注意:若是应用程序已经由于字段过多而变慢,仅编辑设计元素是于事无补的;您必须编写代理程序遍历现有文档,并从中删除多余的条目。已经出现一些业务合做产品能够简化这个过程。不过,若是您的更改是一个重大的重组,好比将一些字段移动到特定的响应文档中,那么代理程序的编写是至关复杂的。设计时从长远考虑,争取第一次就把事情作好,这能节省不少时间。
有些表单无节制地使用图像,对背景使用大型位图以及使用许多其余图像修饰。大图像须要更长的加载时间、占用设计元素的缓存,而且查看表单时须要更长的图像呈现时间。建立表单时稍加注意就能够获得比较专业的外观,而且不会对性能形成太大的影响。下面是一些技巧:
- 不要将图像复制粘贴到表单上;相反,要么使用图像资源设计元素,要么导入图像。若是您计划在多个表单中使用同一个图像,那么可使用图像资源,由于它容许客户端将图像与表单设计分离,而后再缓存它。即便您不打算 在多个表单中使用同一个图像,将图像做为资源也是一个不错的主意,由于之后其余人可能须要使用该图像建立另外一个表单。
- 将图像放到表单上以后,不要随意缩小它的尺寸。使用图像编辑器(好比,GIMP)将原始图像缩小为您所需的尺寸 —— 即便您须要的是同一图像的多个大小不一样的图像资源,也必须这么作。
若是图像的格式为 JPEG,那么能够尝试不一样的压缩设置,看看能不能减少它的体积。JPEG 压缩是“有损耗”的,所以压缩后图像可能会失真,但若是您在不影响视觉效果的状况下最大限度地压缩图像,能够加快表单的加载速度。您能够购买图像工具,它们能帮助您找到一个平衡点。
- 对图像使用正确的文件格式。若是图像使用有限的调色板(就像大部分徽标),GIF 格式的图像文件多是最小的。若是使用全色照片或绘画,JPEG 多是更好的选择。不要使用 BMP 格式的文件,由于它们的压缩比很小。
- 呈现表单元格和图像单元格的背景须要必定的时间。隐藏单元格边框的表单比显示边框的表单的呈现速度快,尤为是使用 3-D 效果的边框。与嵌套在其余表内部的表相比,使用合并单元格的表的呈现速度更快。
不要使用存储表单。
通常不要使用表单选项“Automatically refresh fields”。这个选项会在编辑表单时频繁刷新它,从新计算已计算字段和输入转换公式,从而形成延迟。使用字段级别的选项“Refresh on keyword change”或字段事件 Onchange 或 Onblur 会更好,它们只在须要时进行刷新。
表单能够从其余设计元素获取信息,好比图像资源、共享字段、共享操做、子表单、摘要、样式表和脚本库。打开一个文档可能会从除表单以外的许多其余设计元素读取信息,读取过程是须要时间的。共享设计元素的优势是使应用程序的维护更加容易,而它的不足之处是访问多个元素须要更长的加载时间。
Lotus Notes 缓存设计信息,所以不须要每次都从原始设计元素读取设计信息;然而,首次加载多是个问题。缓存意味着使用共享设计元素能够提高性能,若是须要在许多不一样的表单中使用相同的子表单或图像的话。
共享操做不会损害性能,由于仅有一个设计元素包含共享操做,因此多添加几个共享操做与使用一个共享操做所需的开销是同样的。共享视图列也不会影响性能。
因为共享设计元素有利于维护,因此除非采起各类措施仍然不能获得能够接受的性能,不然不推荐取消设计元素共享。
因为如下缘由,低效和没必要要的视图会形成延迟:
- 打开视图时须要时间更新索引。
- 当在 @Db 函数中使用视图时,须要时间获取信息。
- 服务器上的更新任务会按期检查每一个视图,看看是否须要使用最近修改的文档更新它们。所以视图越多(或越复杂),就越长时间地占用服务器,致使全部应用程序变慢。
视图打开缓慢的另外一个常见缘由是数据库中存在大量文档。当您打开视图时,Lotus Notes 将检查在最后一次视图索引更新以后是否修改了某些文档。您拥有的文档越多,检查所需的时间就越长,即便最终结果是“没有最近修改的文档”。
已经有许多文章介绍在不使用 @Today 或 @Now 时如何提供基于日期/时间的视图。其中的一个例子就是 IBM Support Web 站点技术文档 Time/Date views in Notes: What are the options?,它提供一些建立基于日期/时间的视图的方法。
如今咱们对其余几个方面进行讨论。首先,常常建议使用的@TextToTime(“Today”) 是不完整的。如今它仅适用于第一天。您必须修改它,让它可以正确地工做。
为何?通常状况下,当您打开一个视图时,Lotus Notes 就会查看“视图索引” —— 视图中存储的文档和行值的列表 —— 并仅检查自索引最后一次更新以后建立或修改的文档,以决定是否将它们添加到视图,或删除它们,或从新计算它们的列值。若是自从最后一次使用视图以后没有修改任何文档,这个过程就会很快。
不过,若是您使用 @Today,旧的视图索引就没有用了。例如,假设选择公式为:
SELECT Status = “Processing” & DueDate <= @Today
|
能够将文档添加到该视图,
即便这些文档并无改变,由于自从上一次使用视图以后,@Today 的值就改变了。所以您每次使用这个视图时,Lotus Notes 都会丢弃旧的视图索引,并查看
数据库中的每一个文档,以决定这些文档是否属于该视图,或从新计算列值。
假设您有一个列,若是“请求”文档在3个小时以后仍然打开的话,它将显示一个红色的感叹号(使用 @Now 测试它)。这种状况会发生变化,即便在5秒钟以前还在使用该视图。然而使用 @Today 时,下降视图索引的更新频率可能更好。
您可使用视图属性对话框中的视图索引选项实现这个目的。在 Advanced options 选项卡上,您能够将视图更新指定为“Auto, at most every x hours”,其中 x 是您指定的值。这样作的优势是大大加快了视图的打开,但同时也存在缺点,那就是视图不会当即显示文档更改,
即使文档已更改。用户必须手动刷新视图才能看到最新的数据。
另外一个流行的代替办法就是建立一个在夜间运行的调度代理程序,它经过更新视图选择公式(使用 NotesView.SelectionFormula 方法)来包含当天的选择公式。例如,代理程序可能包含如下语句:
view.SelectionFormula = {SELECT Status=“Processing” & DueDate=[} & Today & {]}
|
不过,它也有一些缺点:
- 在全部副本显示正确的文档以前,必须在全部地方复制视图设计更改。
- 服务器管理员可能不信任更改产品应用程序的设计的代理程序。
- 次日早上打开视图的第一位用户仍然须要等待索引视图。您能够将视图索引选项设置为“Automatic”,或让代理程序刷新视图,这样就可以避免这个问题。
- 若是数据库从模板获取设计,您的视图将被模板覆盖。为了不这个问题,您可让代理程序在夜间设计刷新以后再运行,或将更改应用到模板。
另外一个办法就是在用户界面上作出让步。例如,您能够对视图使用 “open requests by due date ”而不是“open requests that are overdue”,以在视图的顶部对延迟的请求进行排序。它们很容易实现,实现以后视图的打开会快得多。
在一些状况下,适合使用文件夹根据日期条件显示一组文档。在夜间运行的代理程序可使用知足该日期需求的文档填充这个文件夹,而且文件夹上的访问设置能够阻止用户手动更改其内容。若是在白天编辑文档时须要更改文件夹的内容,这就不是一个好选择(虽然比较繁琐,但您还可使用定制代码进行管理)。
许多应用程序很慢,由于它们包含太多视图,删除一部分视图将有所帮助。性能影响通常出如今服务器上,而不是特定的应用程序。
注意:数据库的设计器不必定要访问每一个视图。用户的“Server private”视图和其余带有读者列表的视图是不可见的,但它们仍然会影响性能。服务器管理员能够在“Full access administration”模式下查看这些视图。
默认的视图刷新设置(Auto after first use, Discard index after 45 days)意味着超过 45 天后不使用的视图索引将被丢弃,而且服务器不会再刷新它们。在这点上,它们对服务器性能的影响是很小的。然而,在摘要中使用视图可能会致使用户在搜索所需视图时意外地使用它们。
所以,经过仅包含必要的视图(用于完成用户的特定任务,其命名方式便于用户辨认),您不但能够改善性能,并且还提供更好的用户体验。
一般须要为某个目的建立一次性使用的视图,而且没有程序记录谁须要它们,谁使用它们,以及什么时候可以安全地删除它们。它们经常是“Server private”视图,仅对它们的建立者是可见的,但它们仍然会影响性能。限制建立此类视图可以保持更好的性能(若是您想看看有哪些私有视图,服务器管理员可使用“Full access administration”模式列出它们)。
咱们推荐对视图使用 Comment 字段,用于描述视图的任务、使用者和超过该日期就能够删除视图的“过时”日期(若是知道的话)。这样,若是您对是否有必要使用视图存在疑问,您至少知道应该问谁。若是您想删除一个视图,看看是否有人反对,能够将其复制粘贴到另外一个未包含有文档的数据库,这样您就能够在须要时找到它。
一般,应用程序包含的视图仅是排列方式不一样而已。这些视图应该使用可从新排序的列合并到一个视图中。尽管添加剧新排序列的成本很高,但这要比拥有第二个视图的成本低。
若是您在 Lotus Notes 8.0 中使用新的列选项“Defer index creation until first use”,那么就更应该这样作了。这个选项延迟为从新排序建立索引,直到用户请求它。这会给首位请求用户形成很长的延迟,但若是没有人请求的话,你们都能享受到更好的性能。
当您查找不须要的视图时,要记住,开发人员不必定可以查看应用程序中的全部视图。若是用户在服务器上存储了私有视图,或者共享视图的访问列表没包含您的名字,那么您就不能在设计器中查看这些视图 —— 但它们仍然会影响性能。使用“Full access administration”模式的服务器管理员能够绕过访问控制得到全部视图的列表(并删除任意视图)。
由于服务器必须经过额外工做才能在请求时执行交替视图排序,因此除非有必要,不然不要启用从新排序。升序和降序计数是两种不一样的从新排序,所以除非实际须要,不然不要同时启用它们。在 Lotus Notes 8.0 中,若是您不肯定是否使用了从新排序,那么能够启用该列上的“Defer index creation until first use”选项。
注意,您还能够选择经过单击列的头部,将用户导航到已由该列完成排序的不一样视图,这样您就能够为从新排序提供便利,而且省去额外的工做(若是另外一个视图已经存在)。
咱们倾向于为每一个字段建立一个列,但应该避免这样作。仅在视图中包含用户实际须要查看的信息便可;这样屏幕就不会那么拥挤,而且应用程序的速度会更快,占用的存储空间会更少。
若是视图列公式或选择公式使用了循环函数(@For、@While和@Transform),或除注释以外超过 200 个字符,那么就须要简化它。若是不能简化它,那么考虑将公式移动到表单的计算字段,让视图仅引用字段名。对于在多个视图中使用的公式,这尤为有用。
即便您不使用计算字段,对于较长的公式,稍微思考一下就能简化它。考虑使用 @Select 或 @Replace 代替较长的 @If 语句,并检查逻辑,看看是否可以经过不一样的顺序简化测试。
要注意对列表的全部成员执行操做的运算符和 @Functions。没有必要为字符串列表上的许多简单操做编写循环;例如,要获取每一个元素的前三个字符,可使用 @Left(
listfieldname; 3) 来实现。
咱们还有一些“组合操做符”,好比 *=,可用于比较来自两个列表的组合元素,而且也能帮助您编写更加紧凑的公式。
若是您使用其余语言编写程序,您可能对逻辑运算符比较熟悉,它们仅对可以决定链接值的表达式进行计算。例如,您可能但愿获得这样的表达式:
Form = “Report” & ( Sections = “Financials” | Total > 10000)
|
首先检查 Form 是否是 Report,当这个条件为真时,才测试表达式的其他部分。在宏语言(和 LotusScript)中,逻辑运算符不是这样工做的。表达式的两部分都要计算。因此,若是计算第二部分的开销比较大,您能够选择以下所示的“懒惰逻辑”公式:
@If(Form = “Report”; Sections = “Financials” | Total > 10000; @False)
|
@If 函数的执行时间比 & 运算符长,但若是可以经过它避免执行一些没必要要的大开销函数,您就领先一步了。
分类是很是有用的。它们容许在同一视图的多个标题下列出某个文档。但不要过分使用它,由于在一个视图任务中两次列出某个文档所需的时间几乎翻了一倍。若是每一个文档分别列出在 50 个类别中,再乘以文档数就得出总行数,那么服务器须要存储和计算多少个行?这会给服务器带来很大的压力。
即便您不使用
多个 分类,通过分类的视图仍然比使用简单排序的视图慢。所需的时间取决于行数,而不是文档数,而且每一个文档和类别标题都是一个行。
视图属性对话框包含一组控制视图索引的选项。这些选项不多用到,但选择正确的索引选项可以大大提高性能。
例如,假设数据库包含特定的关键字文档,您须要频繁查找它们以填充表单上的关键字列表。关键字文档是不多更改的,但应用程序中的其余文档则须要常常更改。
在讨论 @DbLookup 时咱们已经知道对这种查找使用缓存是最好的,但第一次必须直接访问视图,由于还不存在缓存值。当您执行这个过程时,Lotus Notes 发如今最后一次使用视图以后文档被更改了,而后将花时间查找被更改的文档,并发现它们并不在视图中。
对于在关键词值 @DbLookup 中使用的视图,不须要在每次使用时都进行从新索引。对于这种视图,使用索引选项“Auto, at most every
x hours”比较合适(见图 2)。
若是没有人使用这些视图,服务器仍然会更新它们,但时间间隔要长些。偶尔可能会有不幸运的用户刷新索引。但这会致使平均查找时间更短,而且同一个用户在复杂表单的每一个查找中都碰到刷新的机会不大,所以使用该选项后表单的打开速度会更快。
若是仅在每一个季度的季度审核时才使用视图,那么将索引保留 45 天没有任何意义。将其设置为在 2 天以后丢弃,这样可以减轻服务器的工做。
在其余状况下,选择适当的索引选项可以改善性能。想办法肯定您的视图应该使用什么设置是值得的。
注意:能够经过程序在当前的副本中刷新索引,好比使用 NotesView.Refresh 方法。假设一个索引在正常状况下不多更新,但当您保存某个向视图提供数据的表单时,则必须更新视图,以在查找中使用新的数据。在表单的 Postsave 代码中,对视图使用 Refresh 方法。同时,您可使用带有 ReCache 的 @Db 函数,将特定查找的缓存更新到视图。
当您须要 Reader 字段时,没有什么东西能够代替它,但它可能会大大损害视图性能。当您打开包含带有 Reader 字段的文档时,Lotus Notes 会对行进行扫描,查找您能够访问的行。当行的数量填满屏幕时,将中止查找。若是您仅能访问一个文档,它必须查看视图中的每一个行进行确认,这可能须要花很长时间。
对此,您能够:
- 使用比较短的 Reader 字段值。在单一角色中检查成员关系要比根据一个长长的访问名称列表比较它们快(使用角色还便于维护)。
- 避免在这种应用程序中使用视图。若是用户仅能访问一两个文档,您能够提供其余访问方式,例如,向他们发送包含有这些文档连接的电子邮件。
- 使用嵌入式单类别视图,这种视图仅显示包含“它们的”文档的类别。
- 使用设置为显示空类别(即未包含文档的类别)的分类视图。固然,这样作使得用户查找文档更加困难,除非您为用户提供导航,所以您应该将该功能和 @SetViewInfo 结合使用,以仅显示用户所需的类别。
注意:使用分类视图存在安全问题;即您在文档中向用户显示了一个字段(类别),他们原本是不能够访问该字段的。要确保使用这种办法是可行的!
- 鼓励用户使用本地副本。由于本地副本仅包含用户可以访问的文档,所以不须要花功夫隔离他们不能访问的文档。
不要单独使用 Reader 字段做为导航帮助;例如,这是一种帮助用户方便地查找所需文档的方法,由于它们是用户可以在视图中看到的全部文档。若是文档中的信息不是隐私的,还有其余更好的方法能够帮助用户找到所需的文档,如前一小节和下一小节所述。
在共享视图的选择或列公式中使用 @UserName 和 @UserRoles 时,不能获得满意的结果。这是开发人员建立仅显示“My Documents”的“Private on first use”视图的常见缘由。这些视图可能存储在服务器上(将从整体上影响应用程序的性能),或者存储在用户的本地“桌面”文件中。
桌面视图不会直接影响服务器的性能,但当打开其中一个视图时,将像其余视图同样进行从新索引,以显示最近的更改。这意味着用户工做站必须向服务器请求自从最后一次使用以后修改的全部文档。这个过程可能形成用户等待,若是许多用户执行该操做,服务器还可能会由于大量发送数据请求而陷入困境。
注意,视图索引仅使用
摘要 数据,所以大型的富文本字段和文件附件在这里不构成问题。
除了性能问题以外,私有视图还面临维护方面的问题,由于开发人员没有简单的方法更新用户私有副本的设计。在这种状况下,共享列也不起做用,由于要在视图中更新共享列,执行更新的人员必须可以访问该视图。
一般可使用 Notes 视图的“single category”功能避免“Private on first use”。例如,若是您正在显示“My Documents”,您可使用根据全部者分类的视图,而后要么使用“single category”公式将该视图嵌入到表单或页面中,要么在视图中的 Postopen 事件中使用 @SetViewInfo,仅对当前用户进行显示。由于只有一个共享视图,因此整体索引开销降至最低,而且私有用户没必要像在桌面私有视图中那样等待,由于索引几乎老是最新的。
当您开始编写 LotusScript 或 JavaTM 代码时,您可能就开始逐步损害性能。在这里,咱们讨论一些常见的问题。
使用 NotesDocumentCollection.GetNthDocument 遍历集合是很是慢的;应该改用GetFirstDocument 和 GetNextDocument。对于某些类型的集合使用 GetNthDocument 也同样高效,但不使用它事情更好办。
若是表单、视图或文件夹有许多操做,您就须要在设计元素中为每一个操做编写代码(使用共享操做也是如此),这样就存储了许多代码,每次使用设计元素时都必须将它们加载到内存中。
在大部分时间,仅用到许多操做中的其中一两个,所以您须要等待加载全部操做。若是操做出如今多个地方,您就在设计缓存中屡次缓存了相同的代码,从而占用应该用于其余用途的内存。
能够考虑将一些操做移动到代理程序中。这样,当有人请求运行操做时,仅在内存中加载一个代码副本。能够用宏语言编写操做按钮,以使用 @Command([RunAgent]) 调用代理程序,这能大大减小随设计元素一块儿加载的代码。
若是您容许用户建立私有视图或文件夹时,这尤其重要,由于他们的文件夹将屡次复制操做代码,这不只占用空间,并且还不能进行更新,除非用户手动删除私有视图。
加载多个脚本库所需的时间并非线性增加的。即加载 10 个脚本库所需的时间比加载 5 个脚本库所需的时间的 2 倍还要多,脚本库使用了其余库时尤为如此。
这在将来可能会获得改变,尽管如此,也存在一个平衡点;访问两个设计元素比访问一个包含相同数量代码的设计元素所需的时间长。将常常一块儿使用的脚本库合并起来可以节省加载时间,尽管有时会加入不须要在特定代理程序中调用的代码。
NotesDocument 的 ComputeWithForm 方法是在文档中更新计算字段但不复制代码的便捷方法。不幸的是,这比“手动”计算和分配新字段值更慢。若是您的代理程序很慢而且使用了 ComputeWithForm,向 ComputeWithForm 添加几行用于为特定字段赋值的代码就可以大大加快程序的速度。
默认状况下,使用 NotesView 对象时,它将为视图实现常规的索引刷新属性。例如,假设您更新一组“Vegetable”文档,做为这个过程的一部分,您必须在同一数据库下的“Pests”视图中查找破坏该植物的害虫。可是当您保存了一个 Vegetable 文档时,另外一个文档又被更改了。
当您处理下一个文档,并查找“Pests”视图时,Lotus Notes 就知道视图索引已通过期,而后刷新它。您所作的更改不会影响 Pests 视图,但在检查已更改的文档以前,Lotus Notes 并不知道这点。
对于这个例子,使用 NotesView 的 AutoUpdate 属性告诉 Lotus Notes 没必要更新视图索引是个不错的主意,除非您使用 Refresh 方法显式地请求它。这可以大大提高速度。
即便您所作的更改影响到 NotesView 的内容,也可使用这种方法,只要您的更改对本身正在作的事情没有影响便可。例如,您知道更新将从视图删除文档,但这没有关系,由于您已开始处理下一个文档。
NotesDocumentCollection 类有一些以“All”结尾的方法,它们可以处理集合中的全部文档。您应该了解这些方法,由于它们比遍历集合和操做每一个文档快得多。(除非您须要对每一个文档执行多个操做;不然遍历会更快,每一个文档仅需保存一次)。
内置类中的某些方法和属性很是慢。若是不须要,就避免使用这些函数,这能让代码的运行更快。例如,假设您处理一个文档集合,必须使用每一个文档的一个字段做为查找值,以从其余视图获取信息:
Dim view As NotesView
Set docCur = coll.GetFirstDocument
Do Until docCur Is Nothing
Set view = db.GetView(“CustomersByID”) 'oops! Don't do this in the loop!
Set docCust = view.GetDocumentByKey(docCur. CustI D(0), True)
...
Set docCur = coll.GetNextDocu ment(docCur)
Loop
|
在这段样例代码中,若是
coll 包含 1000 个文档,咱们将调用开销很大的 GetView 方法
1000 次。若是调换
Do
Until 和
Set view 代码行的位置,代码的运行就会快得多,由于
GetView 仅被调用一次。
使用代理程序探查器查找这类东西是个不错的方法。developerWorks Lotus 文章 Troubleshooting application performance: Part 1: Troubleshooting techniques and code tips 和 Troubleshooting application performance: Part 2: New tools in Lotus Notes/Domino 7 将对此进行描述。
还记得吗,影响性能的因素之一就是修改文档的频率。当您编写处理文档的代理程序时,应该避免没必要要地保存文档更改。在为每一个项赋值时,检查它是否已经拥有该值。若是最终没有修改任何东西,就不要调用 Save 方法。一般,您可使用搜索方法从文档集合中过滤出不须要处理的文档。
若是您老是检查各个项以肯定是否更改它们,代理程序的运行可能慢些。但也可能不变慢,由于保存文档比在内存中比较信息须要更多时间。若是老是执行检查,应用程序的其余部分会更高效,好比复制、视图索引和全文本索引。
避免没必要要的保存也能够减小复制冲突。复制使用
项 修改时间;它并不将整个文档发送给其余副本,而是仅发送修改的项。因此,即便最终须要保存文档,若是只修改须要新值的项,那么就能减小复制时间。使用本地副本的用户将受益不浅。
大部分代理程序必须作的一件事情是查找一组须要处理的文档。有不少查找文档的方法,但不一样的方法适用于不一样的状况。
developerWorks Lotus 文章 Lotus Notes/Domino 7 application performance: Part 1: Database properties and document collections 讨论搜索和处理文档集的不一样方法。下面归纳地介绍一下:
- 若是视图包含您须要的文档,而且以有用的方式进行排序,那么从视图读取文档就会更快,例如使用 GetAllDocumentsByKey 方法。
- 对于包含大量文档的数据库,FTSearch 方法比 NotesDatabase.Search 方法要快,前提是数据库必须是全文本索引的。注意,您也能够经过在代理程序的 Document Selection 事件中输入全文本搜索来执行它。
在这两种状况中,利用服务器事先完成的索引工做能够节省时间。与必须检查每一个文档的 NotesDatabase.Search 相比,FTSearch 节省了一些运行时工做。
全文本搜索的文档过滤级别不如 NotesDatabase.Search 细,但它节省了大量时间,您彻底能够利用一部分时间遍历结果并忽略不适用的部分。在 Notes Client 帮助(不是 Designer 帮助)中的文章“Refining a search query using operators”介绍了完整的全文本查询语法。您将发现它的用途比您想象的要多。
注意:取决于本身的需求,有时您能够结合公式搜索的威力和全文本搜索的性能,在使用基于公式选择条件的视图中进行全文本搜索。
在早期的 Lotus Notes 版本中,使用完 NotesDocument 对象以后,可使用 Delete语句从内存中删除它们。而后,从 6.0 版本开始,不再须要这样作了。(若是您已经知道是怎么回事,就不要再使用它。若是不知道,也不用担忧)。
出于其余非性能方面的缘由,您可能还在使用 Delete,例如,您认为其余进程修改了文档,由于您最终打开它,并确保本身看到的是最新数据。
有一些文章比较了“for”循环和“while”循环、全局变量和堆栈变量等的性能。然而,除非您的应用程序属于计算密集型的,不然难以利用这些比较得到性能改善。
大部分脚本花在打开文档和视图的时间远比处理变量值多。避免没必要要的数组引用能够节省百万分之一秒;然而,打开没必要要的视图可能要花费数秒钟。若是想经过节省时间来提升性能,那么应该先考虑占用时间多的项。
了解不一样 LotusScript 表达式和语句的性能特色可能很是有用,但养成良好的代码编写习惯更有用;回过头来修改不稳当的地方经常是得不偿失的。
关于这个方面的有价值技巧是:
- 不要使用 GetNthDocument(如前所述)
- 显式地声明变量,避免使用默认的变量类型。这样作不只可以提供更好的性能,而且有助于在编译期间查找错误。对于自动将 Option Declare 语句插入到您的 LotusScript 代码中的编程面板属性,应该使用这个选项。
若是将 LC LSX 与外部关系数据库或数据文件整合起来,它一般比内置的 ODBC 类快。
IBM Redbooks Implementing IBM Lotus Enterprise Integrator 6 包含了大量信息,讨论如何使用这个 API 进行编程,以及如何最大限度地提高性能。
这份白皮书在开始时已经提到,不少优秀的小程序在数据和用户的数量比较少时表现很是出色,但当用户和数据很是多时,它们就陷入困境了。使用大量文档测试设计是明智的。测试 50 人同时使用应用程序时有什么反应(您可能很难找到 50 位朋友抽时间参与测试,但可使用可以模拟该场景的自动化测试工具)。
此外,编写包含少许样例数据的代理程序也不是很难,而后经过为选择字段分配随机值增长数据的数量,使文档多达数千个。若是您使用代理选项建立新文档的话(在代理程序编辑屏幕的右下角),这些工做还能够经过公式代理程序完成。
警告:若是您测试已投入生产的应用程序,务必在非生产服务器的数据库拷贝(
不是 副本)上进行测试,而且最好使用不用于复制生产服务器的服务器。这样,就不用担忧破坏生产服务器上的数据,或阻碍使用该服务器的人员的工做。
配置文件文档是高效地储存和获取不常常改变的信息的好办法。由于文档在首次使用时就被完整地缓存起来,因此使用它保存定制关键字列表是很是高效的。这不会影响视图索引,也不用担忧控制缓存。它们的复制和普通文档是同样的(但使用复制选择公式的用户不会意外地破坏应用程序,这比普通的关键字文档要好)。它们既有趣又简单,您能够尝试使用!