内容


Lotus Notes/Domino 7 应用程序性能

第 2 部分:优化数据库视图

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: Lotus Notes/Domino 7 应用程序性能

敬请期待该系列的后续内容。

此内容是该系列的一部分:Lotus Notes/Domino 7 应用程序性能

敬请期待该系列的后续内容。

在 “Lotus Notes/Domino 7 应用程序性能,第 1 部分” 中,我们探讨了如何通过有效地使用数据库属性和文档集合而改善 Lotus Notes/Domino 7 应用程序的性能。在第 2 部分中,我们将解释如何构建高性能的视图。与第 1 部分中一样,本文也提供了许多代码片段,您可以重用和加以修改,从而满足自己的需要。

通过很多年对应用程序性能问题的分析,我们发现问题和解决方案都经常涉及到视图。通常,视图索引就是问题。本文解释这如何会发生,以及您可以采取什么措施来诊断和解决这种类型的问题。但是过去几年里出现得更频繁的是另一种类型的视图性能问题。这涉及到显示读者访问受控文档(reader access controlled document)的视图。这些视图中出现的性能问题通常与索引无关,所以我们要花点时间来分别讨论这些问题。

本文假设您是一位有经验的 Notes/Domino 应用程序开发人员。

理解视图索引(Update 任务)

在诊断涉及视图索引的性能问题之前,您必须知道的第一件事是,索引过程是如何工作的。索引一般由 Update 任务来完成,该任务每 15 分钟在 Domino 服务器上运行一次。技术上说,可以调整这个间隔,但是这涉及到重命名文件,所以实际上很少这么做。

当 Update 任务运行时,它查找服务器上每个在 Update 任务最近一次运行之后进行了修改的数据库。然后它会刷新这些数据库中的视图。根据我们的经验,假定刷新生产环境中生产数据库中的一个普通视图要花大约 100 毫秒是合理的。

要问的逻辑问题是,“什么标志着视图需要更新?” 每当下面任何一种情况出现时,视图就需要更新:

  • 副本发送一个文档修改到数据库。
  • 用户保存或删除一个文档(并退出数据库)。
  • 路由器传递一个文档。

在如何确定视图是否需要更新方面,Update 任务非常灵活。例如,假设您打开了邮件文件,除修改了备注(memo)的 BCC 字段外没做其他改动。没有视图显示了该字段的内容,所以实际上没有视图需要刷新。但是尽管如此,包含该备注的视图至少会被简单地检查,因为服务器不确定您所做的编辑是否会强迫更改这些视图。

这有点绕:通过打开视图或者在修改文档时处于视图中,用户可以强迫一个即时高优先级请求刷新一个视图。下面我们来看一个例子。

假设 Alice 在上午 9:02 打开视图 #1 的 Contact Management 数据库。也假设 Update 任务方便地在 9:00:00 运行,并将在 9:15:00、9:30:00 等时刻再次运行。Alice 在 9:05 更新了一些文档,即创建新文档,编辑现有文档,或者删除文档。无论哪一种情况,服务器都会立即更新视图 #1,因为她处于该视图中。如果您删除了一个文档,而还会在该视图中看到它,那是不是有些奇怪?所以视图被立即更新。但是其他视图都在排队等待到 9:15 进行更新。

现在假设 Bob 在上午 9:02 时也在我们的 Contact Management 数据库中。他是在视图 #1 中工作。在 9:05 时,他在左上角看到了蓝色的重新加载箭头,这告诉他视图已经更新。他可以按 F9 键或单击重新加载箭头,视图很快就会显示已更新的内容。他根本不需要等待刷新。

此外,假设 Cathy 在上午 9:02 时也在该数据库中,但她是在视图 #2 中工作。如果她不做任何事情来在这期间强迫进行刷新(这是可能的,但是也是不一定的),那么在 9:15 当她的视图被 Update 任务刷新时,她会看到蓝色的重新加载箭头。但是更可能的是,Cathy 自己做了一些数据更新,足够地滚动视图以强迫一个更新,或者切换视图。这些动作中的任何一个都会强迫一个即时更新。

在 9:15,这些客户没有强迫刷新的所有视图都进行了刷新,我们又重新开始。

有关视图索引的附加信息

我们发现有两个附加信息有用。第一个是全文本索引器(indexer)。一般来说,标志为立即更新的全文本索引会在几秒钟内(如果服务器忙,就在几分钟内)更新。每小时的全文本索引由 Update 任务按适当的时间间隔而更新(触发)。每天的全文本索引由 Updall 任务在晚上运行 Updall 时而更新(触发)。

第二个附加信息是,开发人员可以在视图设计属性中设置索引选项。很多人误认为这些选项是影响 Update 或 Updall 任务将如何运行的设置。实际上不是这样的。Update 和 Updall 任务会完全忽略这些设置,而只是根据前一个例子中描述的条件来更新视图。

索引选项影响客户打开视图时发生什么。例如,如果这些选项被设置为 manual,那么用户会很快得到视图的一个版本(可能是旧的)。如果被设置为 “Auto, at most every n hours” 且大于指定的时间间隔,那么用户将必须在视图更新时等待一会儿,就像它是一个视图索引选项为 Automatic 的常规视图一样。在本文后面,我们将讨论如何使用这些索引选项来帮助形成有用的视图。

有关诊断视图索引的快速提示

在经过良好调优的环境中,索引应该是相当透明的;视图和全文本索引应该很快更新。在有性能问题的环境中,可能会看到以下征兆:

  • 在打开数据库、打开视图、切换视图、滚动视图或保存文档时有很长的延迟。
  • 在打开使用查找的文档时有延迟(实际上,您会在某些点上看到表单暂停,因为它要等待计算这些查找)。
  • 在整个工作时间都有性能问题,但是下班后的性能很好。
  • 过期的全文本索引。

下面的日志和调试 Notes.ini 参数有助于解决这些问题:

参数描述
log_update=1将额外信息写入 log.nsf Miscellaneous Events 视图。这包括每次 Update 任务开始更新一个数据库时的一行信息,以及 Update 任务完成该数据库时的一行信息。每行都有一个时间/日期戳,所以通过相减可以得到更新该数据库所需的大概时间(舍入到秒)。
log_update=2将更多的信息写入日志。除了由 log_update=1 生成的数据之外,该设置还为每个数据库中的每个视图增加了一行信息。因此,一个具有 75 个视图的数据库应该有 77 行信息 —— 一行指示 Update 任务开始更新该数据库,75 行是每个视图一行,最后一行指示该数据库索引的结束。
debug_nif=1debug_nif 是到目前为止收集索引信息最罗嗦的方法,它会将信息写入一个文本文件(例如,您可以使用 debug_outfile=c:\temp 来指定这个文件)。这很容易每小时生成上千兆字节的数据,所以即使不是完全不用,也应该少用这种方法。这个调试变量的价值在于,它给予您所有索引活动的毫秒级精度,而不像 Update 任务一样只是每 15 分钟运行一次。
client_clock=1使用在客户机器上,而不是服务器上,这会将大量的信息写入一个文本文件(例如,您可以使用 debug_outfile=c:\temp 来指定这个文件),将分解您所执行的每个客户动作。这可用于确定(例如)客户看到的延迟是不是一直在等待索引造成的。

为了诊断视图索引问题,首先通过设置 log_update=1(若还没有设置的话) 来从 log.nsf 收集一些数据,并允许服务器收集一天关于视图更新的信息。然后审查这一天的 log.nsf Miscellaneous Events 视图并寻找模式。可能会出现的一些有意思的模式有:

  • 一个特定数据的非常长的更新时间。这可能表示该数据有太多的数据要更新,有太多复杂的视图,或者有时间/日期敏感的视图(如果服务器是版本 5 或更早版本的话)。逻辑上的下一步是检查该数据库的业务使用和设计,也许还要使用一天 log_update=2 来指出该数据库中哪些视图有问题。
  • 非常长的更新周期。我们已经看到过持续四到五个钟头的周期,这意味着不是每 15 分钟遍历一次所有修改过的数据库,Update 任务可能一天只进行两到三次遍历。这可能指示影响所有任务的一般性能问题,或者指示服务器上非常高的用户或数据负载。逻辑上的下一步是评估服务器上的一般状态和其上的业务使用。

每当发现更新时间比较长时,应该注意一下同时还在运行其他哪些任务以及这些任务是否表现正常。还应该注意出现较长索引时间的情况是否普遍,只出现在繁忙时间,还是只出现在某些尖峰时刻,比如每两个小时一次。做一次观察很少能够得到解决问题所需的所有信息,但是一般会将您引到正确的方向。

视图性能测试

为了测试各种特性和构建视图的方式的性能,我们创建了一个具有 400,000 个文档的数据库,并运行了一个预定的代理来每五分钟更新 4,000 个文档。我们然后构建了大约 20 个视图,每个都具有稍微不同的特性,但是每个视图都使用五列显示所有 400,000 个文档。我们后面将给出详细情况,但是大致情况如下:

  • 视图的大小与重建和刷新该视图所需的时间非常相关。如果视图的大小加倍了,那么重建或刷新该视图所需的时间也会加倍。所以,(例如)如果您有一个 100 MB 的数据库,并且预期它的大小每六个月就会加倍,若发现建立索引现在需要大约 30 秒,那么六个月后就需要 60 秒了,再六个月后就需要 120 秒了,依此类推。
  • 视图索引方面的最大 “性能杀手” 是已分类的列。与其他特性一样(比如 Generate unique keys 选项),排序列会增加一些小小的开销(关于这一点的更多信息,参见本文末尾的一些提示)。

图 1 和图 2 说明了视图大小与刷新时间之间的关系以及已分类列给视图性能带来的重大开销。图 1 描绘了视图索引大小与响应时间。

图 1. 视图索引大小与响应时间
视图索引大小与响应时间
视图索引大小与响应时间

图 2 展示了视图大小及刷新时间。

图 2. 视图大小与刷新时间
视图大小与刷新时间
视图大小与刷新时间

在这两个图中,第一个和第三个分类视图最初是展开的,而第二个和第四个视图最初是折叠的。折叠分类视图可以缩短一点点(但是可以辨别出来)刷新时间。

Reader Names 字段

过去几年里,我们看到与 Reader Names 字段和视图有关的关键情形在数量上有了极大的增加。客户经常发现性能在一天内都不好。他们不能理解这是什么原因,因为代码审查和典型测试都很顺利。但是在传播到他们的整个部门/分公司/公司几个月之后,他们发现关于性能的抱怨是员工之间谈论的主要话题,必须采取一些措施了。

例子

我们喜欢的例子是 HR 和 Sales Force 应用程序 —— 两者一般都有严格的 Reader Names 控件。下表给出了一个公司的假想场景,该公司使用一个具有 400,000 个文档的数据库。

职务/角色用户可以看到的文档个数(400,000 个以上)数据库百分比
公司 HQ、CEO、CIO、Domino 管理员、开发人员400,000100%
区域经理4,0001%
经理4000.1%
员工400.01%

上层管理人员和 Domino 管理员及开发人员一般都感觉到性能很好,这使得关于性能差的最初一些报告容易被忽略。性能问题一般会因较弱的连接(WAN 与 LAN)而加剧,这也容易使得早期的抱怨不起作用。但是登记了很多抱怨之后,有些人来到员工的工作站边上坐下,看一下打开数据库或保存文档到底要多长时间,然后警报才开始响起。图 3 展示了用户在具有 400,000 个文档的示例数据库中打开一个视图要多长时间。所有视图都已经刷新了。测试服务器上没有其他活动在进行,一次只有一个用户在访问服务器。

图 3. 打开示例数据库中的一个视图所需的时间
打开示例数据库中的一个视图所需的时间
打开示例数据库中的一个视图所需的时间

用户由他们可以看到的文档百分比来指示。如果您看不到条形图,就意味着非常接近于零。

在开始解释 Reader Names 字段和性能之前,我们想要给您留下一个关于图 3 的思考:您很快就会看到,为什么平面(已排序的,不是已分类的)视图的用户如果是 0.01% 用户和 100% 用户,他们对该应用程序的性能的影响会如此大不相同。

理解 Reader Names

当应用程序使用 Reader Names 时,意味着一些或所有文档具有 Reader Names 字段 —— 即是 Summary Read Access 的字段。Summary 意味着数据可以显示在视图中。技术上说,您可以创建 Reader Names 字段并阻止它们具有 summary 标志,但是然后 Lotus Domino 不能在视图级别正确地确保文档的安全性。Read Access 只意味着谁可以看到该文档。一般来说,个人名称、组名称和 [角色] 填充这些种类的字段。我们鼓励只要可能就尽量在组上使用 [角色] ,这是由于维护和控制方面的原因,但是从性能上来说,这些都是一样的。

当用户打开一个包含这些读者访问受控文档的视图时,服务器必须确定该用户是否有权看到每一个文档。服务器是非常有秩序的,从上往下检查每一个文档。该过程类似于:

  • Lotus Domino 检查文档 #1,确定用户可以看到它,然后再显示它。
  • Lotus Domino 检查文档 #2,确定用户可以看到它,然后再显示它。
  • Lotus Domino 检查文档 #3,确定用户不能看到它,然后向用户隐藏该文档。

该过程继续进行,直到 Lotus Domino 检查了视图中的所有文档。当然,视图首先必须刷新,否则服务器不知道哪个文档是 #1,或者不知道它的 Reader Names 值是什么。我们先暂停这方面的解释,来考虑一个关于差性能的经典例子。暂时假设我们的数据库是一个 Sales Tracking 应用程序,并且有一个 By Revenue 视图,该视图按契约大小降序存储。假设该视图有五列,前面两列已经排序(例如,Revenue 和 SalesRep)。其中没有类别。在本例中,当用户打开视图(一个可能显示 400,000 个文档的视图),如果需要的话,该用户首先强迫进行一次刷新,然后服务器从文档 #1 开始检查该文档是否可以显示给用户,然后依次检查文档 #2、#3,等等。

您可能是通过 Web 浏览器阅读这篇文章,您也可能了解这样一个事实,即浏览器呈现页面的某些部分(文本)比较快,而呈现另外一些部分(比如图形)则要慢得多。但是 Domino 服务器不这样对待视图,它要直到有了全屏信息之后,才向用户发送视图数据。对于实际目的来说,比如说这可能是 60 行数据。您可以用一个 Notes 客户机,通过打开一个平面视图(没有已分类的列)并按向下箭头键来自己测试这一点。首先,视图快速地滚动。然后出现暂停,这是因为服务器为您呈现另外几 KB 数据。然后视图再次快速滚动另外 60 行左右。只要您按下箭头键,这个过程就会重复出现。

回到我们的用户:事实表明他可以看到文档 #1,但是也许看不到接下来的 10,000 个文档。为什么呢?也许他只能看到整个数据库中的 40 个文档。因为 Domino 服务器在可以构建大约 60 行信息(或者达到视图底部)之前,不会向他展示任何东西,所以这会有一个较长时间的等待。

这就是用户所体验到的。在服务器检查每个文档时,他们有时要等待几分钟。在用户看到的文档太少以致不能填满整个屏幕的情况下,服务器在向用户发送允许他看到的部分屏幕数据之前,会遍历整个视图。

有些读者知道这个功能。有人则对此感到痛苦。您可以把这些人想像为例行公事地分析应用程序性能问题的人,而这类问题是我们很快就将分析并利用替代方法(workarounds)解决的问题。

一个经验是让视图分类。这有助于性能的原因是,类别将总会被显示,并且它们接受一行数据。所以在我们的例子视图 By Revenue 中,用户将很快看到很多类别显示出来,比如 Revenue 和 SalesRep。单击折叠器(twistie)打开任何类别会导致到服务器的一个快速轮回,以确定底层文档对该用户是否可见,但是这离一下子检查 400,000 个文档还差得太远。

另一方面,若发现实际上用户单击的每个折叠器都展开却没有展示任何文档,那会令人沮丧的。在我们的例子中,还有其他一些可能的替代方法,但是我们可以断言,一个按收入展示所有文档的视图可能不是这样的视图,即用户对应该访问的数据库只具有 0.01% 的访问权。这是他们的访问权限上的一个矛盾。但是存在很多这样的情况,即有必要让许多用户访问一个包含了多于他们应该看到的数据的视图。在本节的结尾,我们列出了一些提示,即关于如何在具有读者访问受控文档的数据库中构建快速视图。

我们对 Reader Names 和视图有两个接近的想法。首先,在正常的生产环境中,很少会得到像我们在图 3 中具有的如此清晰的数据。您很可能会看到,由 Reader Names 引起的性能问题会导致大量其他性能延迟,比如代理、视图索引,等等。这些问题还会导致其他问题。例如,您可能注意到视图对于每个人来说都很慢,从而推导出问题在于视图索引 —— 当底层问题在于 Reader Names 在用户打开视图时强迫服务器进行长时间的计算时。

其次,我们的测试(和图 3)代表一个绝对最佳案例场景。原因在于我们一次只有一个用户。我们可以利用预定的代理来重复数据容量甚至索引问题,但是我们的测试不能展示当很多用户同时试图访问具有读者访问受控文档的视图时引起的螺旋式性能问题。如果您的应用程序使用了 Reader Names,那么您若要避免危机,就绝对要注意视图性能。

有关读者访问受控文档的性能增强提示

下面这些提示旨在构建针对读者访问受控文档也执行良好的应用程序/视图:

  • 使用 Show Single Category 的嵌入式视图。这是胜利者,把手放下。如果您的数据是结构化的以致用户可以在一个类别中看到所有文档,那么您可以非常快速地只将该类别的内容显示给用户。在有些情况下,让用户切换类别是有意义的,在这样的情况下,您必须考虑他是否可以看到其他类别的内容。但是在大多数情况下,视图应该有些类似于 My Sales,并将为当前用户展示所有销售文档。对这种视图的告诫是,Notes 客户机的用户界面没有本机视图显示的那么好。对于 Web 浏览器来说,它已经很好了,我们还没看到过不要对 Web 浏览器应用程序使用这种视图的理由。实际上,性能很好,打开一个这种具有读者访问受控文档的视图,比打开不具有读者访问受控文档的本机视图还要快!
  • 本地副本。对于销售跟踪数据库来说,很多公司使用本地副本来确保其销售代表能够在断开连接的情况下使用数据库。从许多方面来讲,这都是一个很好的解决方案,但是读者访问受控文档在其 Reader Names 值改变时会很麻烦,它们需要从一些本地副本上消失,而出现在另外一些副本上。
  • 首次使用时是共享和私有的视图。这对 Notes 客户机来说是一个很好的解决方案,但是也存在一些缺点。首先,它不能用于浏览器。其次,视图需要存储在本地或者存储在服务器上,前一种情况对于有些客户来说是个问题,后一种情况是其本身的一个性能和维护问题。第三,随着应用程序设计的改变,它在更新这些私有视图的设计方面会很麻烦。第四,有些客户体验到了性能问题,这可能与创建和使用了大量的私有视图有关。
  • 分类视图。如图 3 所示,相对于 Reader Names 来说,分类视图可以非常快被打开。它们比较大且索引较慢,但是它们一般消除了 Reader Names 性能问题。这里真正的告诫是,用户可能会发现这些视图是不友好的,就像是一个没有人愿意用在其应用程序上的标签。

最后一个提示关系到一些需要避免的事情。特性 “不显示空类别” 在理论上可以很好地与前一个提示一起使用,以构建这样一个分类视图,即只显示包含用户可以看到的文档的类别。但是在实际中,它将导致一个具有类似于平面视图的性能特征的视图,所以如果性能很重要,它可能是一个应该避免的特性。

一般视图性能提示

下面是关于视图性能的一些提示,而不管是否有读者访问受控文档。

时间/日期公式

在列或选择公式中使用 @Now 或 @Today 会强迫视图在每次刷新时重建。因此,如果使用这种公式,请考虑将视图刷新设为 Manually 或 “Auto, at most every n hours”。这样,当用户打开视图时,就不必等待视图重建(或者至少说很少需要等待)。但缺点是,视图可能会过期,因为它打开时没有尝试刷新。请考虑这些视图的内容以及它们改变得有多快,以确定您是否可以安全地使用这些索引选项。

明智地使用点击排序

点击排序(click-sort)是一个很好的特性,我们将它用于应用程序中的大多数公共视图中。但是应该检查您的隐藏查找视图,以确保所有列都没有启用点击排序,因为启用该特性会增加磁盘空间和索引需求,而不会给用户增加任何功能。对于这同一个主题,当您使用该特性来节省磁盘空间和索引时间却不妨碍功能时,请考虑使用升序或降序,但不能同时采用二者。我们将证明该功能在只有一个箭头时更好一些,因为它是一个开关控件,而不是三向控件。

在索引中生成惟一键

一个比较不为人知的性能增强特性 —— 针对查找视图的 “Generate unique keys in index(在索引中生成惟一键)” 选项 —— 可以大大缩短查找时间。当选中该选项时,视图将丢弃所有重复的项。例如,如果您具有 400,000 个文档,所有文档都只显示 CompanyName,并且只有 1,000 个惟一的公司名,那么选择该特性会导致只有每个公司的第一个文档出现在视图索引中。尽管该特性只有很小的开销,但是也很容易超载,因为视图极大地缩小。一个警告是,如果您显示多值字段的结果,那么您需要使用一个代码技巧来避免丢失数据。

例如,假设一个数据库具有 100,000 个文档,所有文档都包含一个叫做 Industry 的多值字段。您想要查找已经选中的行业的惟一列表,以便当用户创建新文档时,Industry 下拉列表可以显示这些值。如果您在一个具有单个显示 Industry 的列的视图中使用这种惟一键特性,那么有可能新文档中会包含 Automotive 和 Air 不能显示的值,因为另一个包含 Automotive 的文档已经显示在该视图中。因此,Air 的新值将永远不会被查找公式找到。

为了避免这个问题,请在列公式中使用一个诸如 @Implode(Industry; "~") 这样的公式,然后下拉字段查找公式将为 @Explode(@DbColumn("Notes"; ""; "(LookupViewName)"; 1); "~")。尽管您将在视图中具有一些重复数据,但是能保证不会丢失数据。

颜色设置

如果您使用颜色设置(color profiles),就像在邮件模板中一样,那么该颜色设置文档的任何更改都会导致引用该颜色设置的任何视图进行重建。

默认视图

每当您的应用程序被打开,默认视图就被打开。请总是确保该视图是一个可很快打开的视图。一个有趣的例子是邮件文件。对于许多用户来说,默认打开的视图是 Inbox(文件夹)。如果一个用户不习惯清理她的 Inbox,并且其中有了成千上万个文档,那么比起她经常清理 Inbox 并且视图/文件夹中只有几十个或几百个文档的情况来说,打开邮件文件将会慢一些。顺便说一句,这就是为什么有些公司要制定政策,定期地删除 Inbox 中的旧文档。这会迫使用户将那些文档移动到其他文件夹中去,从而为该用户和服务器改善性能。

结束语

我们希望您能从本系列文章总结出,应用程序的性能是您可以改变的。通过深思熟虑地应用一些常识(也许还有本文中包含的一些信息和提示),您可以让应用程序的性能保持在大大高于用户刚刚能够接受的水平。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Lotus
ArticleID=107141
ArticleTitle=Lotus Notes/Domino 7 应用程序性能: 第 2 部分:优化数据库视图
publish-date=02142006