Lotus開發效能優化

hannover發表於2016-02-03

之前也總結過一篇關於效能的文章,地址在http://www.cnblogs.com/carysun/archive/2008/08/09/BasicPerformance.html,今天又看到DW上又有一篇很好的關於Lotus效能的文章,放在自己的blog中方便查詢。

1.主要因素

一般而言,以下因素對應用程式的效能影響最大:

  • 檢視的數量及其複雜性。刪除不使用的檢視或合併相似的檢視。對於包含相同文件但使用不同排序的檢視,使用一個可重新排序的列合併它們。刪除不需要的列,並簡化選擇和檢視列公式。檢查是否存在您不能訪問的“伺服器私有”檢視或其他檢視。
  • 在檢視選擇公式或列選擇公式中使用 _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 也討論了類似的主題。
  • 使用者數量。如果伺服器上存在大量使用者,那麼將會影響應用程式和伺服器的效能。當應用程式的效能已經處於臨界狀態時,新增新的使用者會導致效能惡化。改良設計會有所幫助,但您還需要在其他伺服器上建立副本(尤其是叢集伺服器),或鼓勵使用者建立更 快的本地副本。

2.資料庫級別的效能因素

參考 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)。

圖 1. ACL 對話方塊
domino01

如果您取消選擇“Create personal folders/views”,使用者仍然能夠建立私有檢視,但建立的檢視必須儲存在本地的桌面檔案中,而不是儲存在伺服器上。因此不會對應用程式的效能造成太大的影響。

桌面私有檢視肯定會對效能造成影響,因為索引它們時使用者必須從伺服器實時提取資料。因此過多地使用桌面私有檢視還會使伺服器陷入困境。所以要避免為啟用“Private on first use”選項的使用者自動建立個人檢視。(下面會對此進行詳細闡述)。

3.公式效能

大部分 @ 函式都是相當快的,但有一小部分比較慢。因此要謹慎地使用它們:

  • @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

影響 @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)。然後,您就可以在需要顯示名稱的地方使用公式:

CustDetails[1] 等等。 

在重新整理時重複查詢

假設您在組建表單時需要在計算欄位中查詢客戶的經理的名字,如下所示:

@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 函式,它生成一個很短但基本上是惟一的值(通過一些額外的工作就可以保證惟一性,例如為每位使用者新增一個惟一的“字首”,通常是他們的名稱的首字母)。

如果您決定真的需要使用序列號,那麼請閱讀 developerWorks 文章 Generating sequential numbers in replicated applications,它為使用序列號提供一種合理、高效的方法。一篇更多地討論這個主題的 developerWorks 文章即將釋出。

4.表單設計

 

在這個小節中,我們將解決一下值得關注的問題。

能使用 Computed for Display 欄位就不要使用 Computed 欄位

因為儲存欄位一般都會使應用程式變慢,所以如果能夠在需要時輕鬆地計算這些值,就應該避免儲存值。這裡有一個折中;當文件以讀模式開啟時,不會計算 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 快取設計資訊,因此不需要每次都從原始設計元素讀取設計資訊;然而,首次載入可能是個問題。快取意味著使用共享設計元素可以提升效能,如果需要在許多不同的表單中使用相同的子表單或影象的話。

共享操作不會損害效能,因為僅有一個設計元素包含共享操作,所以多新增幾個共享操作與使用一個共享操作所需的開銷是一樣的。共享檢視列也不會影響效能。

由於共享設計元素有利於維護,所以除非採取各種措施仍然不能得到可以接受的效能,否則不推薦取消設計元素共享。

5.檢視

由於以下原因,低效和不必要的檢視會造成延遲:

  • 開啟檢視時需要時間更新索引。
  • 當在 @Db 函式中使用檢視時,需要時間獲取資訊。
  • 伺服器上的更新任務會定期檢查每個檢視,看看是否需要使用最近修改的文件更新它們。因此檢視越多(或越複雜),就越長時間地佔用伺服器,導致所有應用程式變慢。

檢視開啟緩慢的另一個常見原因是資料庫中存在大量文件。當您開啟檢視時,Lotus Notes 將檢查在最後一次檢視索引更新之後是否修改了某些文件。您擁有的文件越多,檢查所需的時間就越長,即使最終結果是“沒有最近修改的文件”。

檢視中的 @Now 或 @Today

已經有許多文章介紹在不使用 @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 都會丟棄舊的檢視索引,並檢視資料庫中的每個文件,以決定這些文件是否屬於該檢視,或重新計算列值。

如果您使用 @TextToTime(“Today”) 而不是 @Today,那麼您就可以“勝過”檢視索引器。祝賀您!Lotus Notes 將重用舊的檢視索引,並僅檢查被更改的文件。這會得到更快的速度,但不幸的是得出的結果是錯誤的,因為當 @Today 改變時,我們必須重新檢查所有文件。 不必要的檢視

假設您有一個列,如果“請求”文件在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)。

domino02

如果沒有人使用這些檢視,伺服器仍然會更新它們,但時間間隔要長些。偶爾可能會有不幸運的使用者重新整理索引。但這會導致平均查詢時間更短,並且同一個使用者在複雜表單的每個查詢中都碰到重新整理的機會不大,因此使用該選項後表單的開啟速度會更快。

如果僅在每個季度的季度稽核時才使用檢視,那麼將索引保留 45 天沒有任何意義。將其設定為在 2 天之後丟棄,這樣能夠減輕伺服器的工作。

在其他情況下,選擇適當的索引選項能夠改善效能。想辦法確定您的檢視應該使用什麼設定是值得的。

注意:可以通過程式在當前的副本中重新整理索引,比如使用 NotesView.Refresh 方法。假設一個索引在正常情況下很少更新,但當您儲存某個向檢視提供資料的表單時,則必須更新檢視,以在查詢中使用新的資料。在表單的 Postsave 程式碼中,對檢視使用 Refresh 方法。同時,您可以使用帶有 ReCache 的 @Db 函式,將特定查詢的快取更新到檢視。

Reader 欄位

當您需要 Reader 欄位時,沒有什麼東西可以代替它,但它可能會大大損害檢視效能。當您開啟包含帶有 Reader 欄位的文件時,Lotus Notes 會對行進行掃描,查詢您可以訪問的行。當行的數量填滿螢幕時,將停止查詢。如果您僅能訪問一個文件,它必須檢視檢視中的每個行進行確認,這可能需要花很長時間。

對此,您可以:

  • 使用比較短的 Reader 欄位值。在單一角色中檢查成員關係要比根據一個長長的訪問名稱列表比較它們快(使用角色還便於維護)。
  • 避免在這種應用程式中使用檢視。如果使用者僅能訪問一兩個文件,您可以提供其他訪問方式,例如,向他們傳送包含有這些文件連結的電子郵件。
  • 使用嵌入式單類別檢視,這種檢視僅顯示包含“它們的”文件的類別。
  • 使用設定為顯示空類別(即未包含文件的類別)的分類檢視。當然,這樣做使得使用者查詢文件更加困難,除非您為使用者提供導航,因此您應該將該功能和 @SetViewInfo 結合使用,以僅顯示使用者所需的類別。

注意:使用分類檢視存在安全問題;即您在文件中向使用者顯示了一個欄位(類別),他們本來是不可以訪問該欄位的。要確保使用這種辦法是可行的!

  • 鼓勵使用者使用本地副本。因為本地副本僅包含使用者能夠訪問的文件,因此不需要花功夫隔離他們不能訪問的文件。

不要單獨使用 Reader 欄位作為導航幫助;例如,這是一種幫助使用者方便地查詢所需文件的方法,因為它們是使用者能夠在檢視中看到的所有文件。如果文件中的資訊不是隱私的,還有其他更好的方法可以幫助使用者找到所需的文件,如前一小節和下一小節所述。

Private on first use

在共享檢視的選擇或列公式中使用 @UserName 和 @UserRoles 時,不能得到滿意的結果。這是開發人員建立僅顯示“My Documents”的“Private on first use”檢視的常見原因。這些檢視可能儲存在伺服器上(將從總體上影響應用程式的效能),或者儲存在使用者的本地“桌面”檔案中。

桌面檢視不會直接影響伺服器的效能,但當開啟其中一個檢視時,將像其他檢視一樣進行重新索引,以顯示最近的更改。這意味著使用者工作站必須向伺服器請求自從最後一次使用之後修改的所有文件。這個過程可能造成使用者等待,如果許多使用者執行該操作,伺服器還可能會因為大量傳送資料請求而陷入困境。

注意,檢視索引僅使用摘要 資料,因此大型的富文字欄位和檔案附件在這裡不構成問題。

除了效能問題之外,私有檢視還面臨維護方面的問題,因為開發人員沒有簡單的方法更新使用者私有副本的設計。在這種情況下,共享列也不起作用,因為要在檢視中更新共享列,執行更新的人員必須能夠訪問該檢視。

通常可以使用 Notes 檢視的“single category”功能避免“Private on first use”。例如,如果您正在顯示“My Documents”,您可以使用根據所有者分類的檢視,然後要麼使用“single category”公式將該檢視嵌入到表單或頁面中,要麼在檢視中的 Postopen 事件中使用 @SetViewInfo,僅對當前使用者進行顯示。因為只有一個共享檢視,所以總體索引開銷降至最低,並且私有使用者不必像在桌面私有檢視中那樣等待,因為索引幾乎總是最新的。

6.程式碼

當您開始編寫 LotusScript 或 JavaTM 程式碼時,您可能就開始逐步損害效能。在這裡,我們討論一些常見的問題。

GetNthDocument

使用 NotesDocumentCollection.GetNthDocument 遍歷集合是非常慢的;應該改用GetFirstDocument 和 GetNextDocument。對於某些型別的集合使用 GetNthDocument 也一樣高效,但不使用它事情更好辦。

表單或檢視包含的操作程式碼過多

如果表單、檢視或資料夾有許多操作,您就需要在設計元素中為每個操作編寫程式碼(使用共享操作也是如此),這樣就儲存了許多程式碼,每次使用設計元素時都必須將它們載入到記憶體中。

在大部分時間,僅用到許多操作中的其中一兩個,因此您需要等待載入所有操作。如果操作出現在多個地方,您就在設計快取中多次快取了相同的程式碼,從而佔用應該用於其他用途的記憶體。

可以考慮將一些操作移動到代理程式中。這樣,當有人請求執行操作時,僅在記憶體中載入一個程式碼副本。可以用巨集語言編寫操作按鈕,以使用 @Command([RunAgent]) 呼叫代理程式,這能大大減少隨設計元素一起載入的程式碼。

如果您允許使用者建立私有檢視或資料夾時,這尤為重要,因為他們的資料夾將多次複製操作程式碼,這不僅佔用空間,而且還不能進行更新,除非使用者手動刪除私有檢視。

指令碼庫過多

載入多個指令碼庫所需的時間並不是線性增長的。即載入 10 個指令碼庫所需的時間比載入 5 個指令碼庫所需的時間的 2 倍還要多,指令碼庫使用了其他庫時尤其如此。

這在未來可能會得到改變,儘管如此,也存在一個平衡點;訪問兩個設計元素比訪問一個包含相同數量程式碼的設計元素所需的時間長。將經常一起使用的指令碼庫合併起來能夠節省載入時間,儘管有時會加入不需要在特定代理程式中呼叫的程式碼。

ComputeWithForm

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 程式碼中的程式設計皮膚屬性,應該使用這個選項。

7.使用 LC LSX

如果將 LC LSX 與外部關聯式資料庫或資料檔案整合起來,它通常比內建的 ODBC 類快。
IBM Redbooks Implementing IBM Lotus Enterprise Integrator 6 包含了大量資訊,討論如何使用這個 API 進行程式設計,以及如何最大限度地提升效能。

8.測試

這份白皮書在開始時已經提到,很多優秀的小程式在資料和使用者的數量比較少時表現非常出色,但當使用者和資料非常多時,它們就陷入困境了。使用大量文件測試設計是明智的。測試 50 人同時使用應用程式時有什麼反應(您可能很難找到 50 位朋友抽時間參與測試,但可以使用能夠模擬該場景的自動化測試工具)。

此外,編寫包含少量樣例資料的代理程式也不是很難,然後通過為選擇欄位分配隨機值增加資料的數量,使文件多達數千個。如果您使用代理選項建立新文件的話(在代理程式編輯螢幕的右下角),這些工作還可以通過公式代理程式完成。

警告:如果您測試已投入生產的應用程式,務必在非生產伺服器的資料庫拷貝(不是 副本)上進行測試,並且最好使用不用於複製生產伺服器的伺服器。這樣,就不用擔心破壞生產伺服器上的資料,或阻礙使用該伺服器的人員的工作。

9.使用配置檔案文件

配置檔案文件是高效地儲存和獲取不經常改變的資訊的好辦法。因為文件在首次使用時就被完整地快取起來,所以使用它儲存定製關鍵字列表是非常高效的。這不會影響檢視索引,也不用擔心控制快取。它們的複製和普通文件是一樣的(但使用複製選擇公式的使用者不會意外地破壞應用程式,這比普通的關鍵字文件要好)。它們既有趣又簡單,您可以嘗試使用!

相關文章