Lotus Notes/Domino 7 アプリケーションのパフォーマンス: 第1部:データベース・プロパティーと文書コレクション

Lotus Notes/Domino のどの開発者も「素晴らしいアプリケーションだが、遅すぎる」というコメントを聞きたくありません。この2部構成の連続記事では、パフォーマンスを最適化した Lotus Notes/Domino アプリケーションを構築することにより、このような評価を避ける方法について説明します。

Raphael Savir, Principal Developer, LS Development Corporation

Raphael Savir, principal developer at LS Development Corporation (http://www.lsdevelopment.com) has been developing Notes/Domino applications and analyzing application performance problems since the early 1990s. He has spoken at Lotusphere and other conferences on several occasions on these topics.



2006年 1月 31日

最も残念な状況の1つは、速度が遅いために素晴らしいアプリケーションが使用されないことです。反応時間の遅さにユーザーが不満を持ち、長時間を費やした大変な作業は無駄になります。パフォーマンスを最適化するには、どのような機能をどこで使用すればよいのかを理解するために、私たちは過去12年間にわたって、Lotus Dominoアプリケーションとその機能の研究およびテストに携わってきました。私たちは、1990年代の初めからLotus Dominoアプリケーションのサポートと開発を開始し、すぐにアプリケーションのパフォーマンスに強い興味を持つようになりました。当時 (そして、今日でも)、サーバーのパフォーマンスの問題と認識されていたことの多くが、実際にはアプリケーションのパフォーマンスの問題であるように見えました。このため、サーバーでなく、アプリケーション内で解決方法を得られることがしばしばあります。

この2部構成の記事では、私たちがこれまでに習得してきたことについて説明します。記事で取り上げるのは、アプリケーション・パフォーマンスの3つの領域であるデータベース・プロパティー、文書コレクション、およびビューです。第1部では、データベース・プロパティーと文書コレクションについて解説します。各ケースについて、最も重要な領域を指摘し、実際のアプリケーションに応用できるように、簡単な実例を示します。これらの例は多くのアプリケーションから得たものなので、実際に行いたいことや使用したいことに近いものが見つかるでしょう。ここでの目標は、優れた機能に見合う実行速度を持ったアプリケーションを構築できるようになることです。

この記事は、Lotus Notes/Dominoアプリケーション開発者としての経験がある方を対象として書かれています。

データベース・プロパティー

アプリケーションのパフォーマンスに関連するデータ・プロパティーは多数あります。

未読マークを使用しない

このボックスをオンにすると、各ビューの設定にかかわらず、アプリケーションで未読マークがトラッキングされません。私たちはclient_clockを使用して、データベースを開くのにかかる時間を測定し、驚くべき結果を得ました。大きなアプリケーション (たとえば、200,000文書がある20GBのアプリケーション) では、未読マークがない場合、Notes Clientはネットワーク・トラフィックも含めて、データベースを約5秒以内に開くことができました。未読マークをオンにすると、さらに6秒以上待たなければなりませんでした。この余分な時間は、GET_UNREAD_NOTE_TABLEとRCV_UNREADに費やされています。未読マークがオフの場合、これらの呼び出しは実行されません。

より小さいデータベース (1GB未満) では、未読マークをオフにすることで、0.5秒ほど短縮されます。もちろん、未読マークの有無にかかわらず、小さいデータベースは大きいデータベースよりも速く開くことができます。このため、アプリケーションを実動環境に配備する前に、未読マーク機能が必要かどうかを改めて考慮する必要があります。

文書テーブルマップの最適化

この機能は、Lotus Notes/Dominoの過去数回のリリースで変更されていません。この機能の目的は、Lotus Dominoディレクトリに似た構造を持つアプリケーションでビューの索引作成をスピードアップすることです。(言い換えると、1つのフォームを使用する文書が多数あり、他のフォームを使用する文書が少数ある構造です。たとえば、Lotus Dominoディレクトリのユーザー文書とサーバー文書の関係です。)

このアイデアは、各文書ノート (document note) をチェックしてビューの索引に含めるかどうかを判断する代わりに、2つのパス (通行証) を作成する、というものです。最初のパスは、その文書に正しいフォーム名が割り当てられているかをチェックします。2番目のパスは、必要な場合に、この文書ノートをビューの索引に含めるために満たさなければならない他の条件をチェックします。

メモ:

現在、この機能は索引作成の時間を改善しないようです (Lotus Dominoディレクトリに対しても)。

空きスペースに上書きしない

この機能は、Lotus Notes/Dominoの過去数回のリリースで変更されていません。このボックスをオフにすると、文書が削除されるたびに、Lotus Notesはデータへのポインターを単に削除するのではなく、実際にデータのビットを上書きします。その目的は、データを回復不能にするためです。この機能は、ハード・ディスクの物理的な安全性を危惧する場合にのみ使用します。ほとんどのアプリケーションで、この物理的なセキュリティーは保証されていないため、これは単にデータを削除するときの追加手順として用いられます。

LastAccessedプロパティを保持

この機能は、Lotus Notes/Dominoの過去数回のリリースで変更されていません。このボックスをオンにすると、Lotus Notes Clientによってデータベース内の各文書が開かれた最終日時が記録されます。もちろん、Lotus Notesは最後に保存された日時を常に $UpdatedByフィールドに記録していますが、この機能は最終の読み取り日時も記録します。(ただし、Webブラウザーからの読み取りは記録されません。)

私たちは、ナレッジベース・アプリケーション以外でこの機能が開発者によって使用された例を見たことがありません。ナレッジベース・アプリケーションでは、一定の期間 (月または年) 文書が読まれないと、そのデータがアーカイブされます。


文書コレクション

私たちは、エージェント、ビュー、フォーム・フィールド式などにある、お客様のコードを長年見てきました。この経験から、フロントエンドのパフォーマンスの問題は、バックエンドのパフォーマンスの問題に比べ、より面倒になる傾向があることがわかりました。その理由として、次のことが考えられます。

  • 一般に、バックエンドプロセスはより厳しくモニターされています。
  • バックエンドプロセスは、多くの場合、ネットワーク・トラフィックを考慮する必要がありません。
  • フロントエンドの問題は、解決が困難な場合があります。ユーザーは、関連するアクションを把握できないことがあり、重要でないアクションや無関係のアクションをサポート・デスクに報告することもあります。

しかし、使われている場所にかかわらずコードが遅いと感じられる場合、その内容を調べると、次のような共通の特徴が得られます。

  • コードが、コンテキストから特定の条件 (ユーザー名、ユーザーが操作している文書の状態、本日の日付など) を作成している。
  • コードが、このデータベースや他のデータベースから文書コレクションを取得している。
  • コードが、これらの文書に対し読み取りまたは書き込みを行っている。

長年にわたるパフォーマンスのテストから、最初の項目は非常に速いことがわかっています。より大きなトラブルがない限り、最適化する価値はありません。3番目の項目は速度が遅くなるケースがありますが、対策としての自由度はあまりありません。一連の文書に対し、コードが効率の悪い方法で情報の読み取りや保存を行っていることに気付かないことがあります。たとえば、今日の日付をDateTodayというフィールドに保存する場合、通常は次のいずれかの方法を使用します。

Extended class
Set Doc = dc.getfirstdocument
Do while not (Doc is Nothing)
Doc.DateToday = Today
Call Doc.Save
Set Doc = dc.getnextdocument ( Doc )
Loop
ReplaceItemValue
Set Doc = dc.getfirstdocument
Do while not (Doc is Nothing)
Call Doc.ReplaceItemValue ("DateToday", Today)
Call Doc.Save
Set Doc = dc.getnextdocument (Doc)
Loop
StampAll
Call dc.StampAll ("TodayDate", Today)

私たちのテストでは、上記の3つの例で、最初の2つには明確なパフォーマンスの差を認められませんでした。拡張クラスの構文「doc.DateToday = Today」は、「doc.ReplaceItemValue ("DateToday", Today)」とほぼ同じ速さとなります。一方のケースでは、フィールド項目の更新をLotus Notesに対して明示的に指示していないので、Lotus NotesはDateTodayがフィールドであることを認識するために、少しだけ長い時間を費やすことになります。このため、理論的にはパフォーマンスの違いがあるはずです。しかし、実際のテストでは違いを検出できませんでした。

前の例で、1つの値で多数の文書を更新する場合は、dc.StampAllメソッドを使用すると、より速くなります。一部のポイント・リリースではバグによってこのメソッドが非常に遅くなることがあるため、最新のリリースを使用していない場合は、このメソッドが良好に機能していることを確認してください (テストするか、修正リストをチェックします)。しかし、Lotus Notes/Domino 6.5および7から、この処理が再び速くなっています。文書に書き込むデータまたは変数データに対し多数のチェックを行う場合は、dc.StampAllが常に実行可能な方法とは限りません。dc.StampAllは有用なメソッドですが、アプリケーションによっては、使用できることも、できないこともあります。

3つの方法のうち最も注目したいのは、これまでの経験によると、Replace ItemValueを使用する方法 (文書コレクションの取得) です。これはコードの実行時間の中でも大きな割合を占めるため、最も圧縮できる可能性があります私たちのテストではこれに重点を置きました。詳細についてはこのセクションで後述します。

テストの実行

テストの実行方法として、同じ数のフィールド (約200個) を持つ、ほぼ同じサイズ (約2K) の文書によって構成される大きなデータベースを1つ作成します。各文書には、慎重に計画的した違いを持たせてあるため、任意の数の文書に対して検索を実行できます。具体的には、1、2、3、・・・9、10個の文書、20、30、40、・・・90、100個の文書、そして 200、300、400、・・・900、1000個の文書に対し、それぞれ検索を実行できます。これによって非常に多数のデータ・ポイントが得られ、ごく狭い範囲だけでパフォーマンスの良否を論じていないことを証明できます。たとえば、db.searchは、データベース内の文書の大きいサブセットに対しては非常に優れたパフォーマンスを示しますが、小さいサブセットに対してはパフォーマンスが劣ります。全域にわたって慎重にテストしないと、パフォーマンスの特性を誤って把握することがあります。

私たちは、一度に長時間のテストを実行し、結果をテキスト・ファイルに書き出しました。これをスプレッドシートとプレゼンテーション用のプログラムに読み込み、XY座標のチャートを作成しました。このような試みを小さいデータベース (1万文書) と大きいデータベース (400万文書) について繰り返し、アプリケーション開発者の方の参考になるガイドラインを得ることができました。

どの方法が最も速いか?

読み出しまたは書き込み用に文書コレクションを取得する最も速い方法は、db.ftsearchまたはview.GetAllDocumentsByKeyのいずれかを使用する方法です。それ以外の方法 (下記のリストを参照) は、一部の文書セット (後述します) では同じぐらいの速さになりますが、小さいコレクションと大きいコレクションの両方で、この2つに匹敵する方法はありませんでした。まず、それぞれの方法を簡単に紹介し、その後で詳細について説明します。

  • view.GetAllDocumentsByKeyは、ビュー内のキーに基づいて文書コレクションを取得し、「set doc = dc.GetNextDocument (doc)」を使用して各文書に順次アクセスします。
  • db.ftsearchは、データベース内の全文検索条件に基づいて文書コレクションを取得し、「set doc = dc.GetNextDocument (doc)」を使用して各文書に順次アクセスします。
  • view.ftsearchは全文検索条件に基づいて文書コレクションを取得しますが、結果はビュー内にすでに表示されている文書に限定されます。次に、「set doc = dc.GetNextDocument (doc)」を使用して、コレクション内の各文書に順次アクセスします。
  • db.searchは、データベース内の非全文検索条件に基づいて文書コレクションを取得し、「set doc = dc.GetNextDocument (doc)」を使用して各文書に順次アクセスします。
  • view.GetAllEntriesByKeyは、ビュー内のビュー・エントリーのコレクションを取得し、列の値を直接読み取るか、ビュー・エントリーを介してバックエンド文書へのハンドルを取得します。次に、「set entry = nvc.GetNextEntry (entry)」を使用して、コレクション内の各文書に順次アクセスします。

小さいデータベース (たとえば、10,000文書) と小さい文書コレクション (たとえば、10前後の文書) の場合は、他の多くの方法も同じようなパフォーマンスとなり、いずれも非常に速く処理されます。これはいわゆる些細なケースで、コードが何回もループしない限り (あるいは、アプリケーション内で頻繁に使用されない限り)、このコードはそのままにしておき、より大きな問題に移った方がよいでしょう。

しかし、たとえ違いが小さくても、多数の文書コレクションを取得しなければならない場合は、1回の実行につき1秒未満の削減でも、結果として意味のある違いとなるでしょう。また、アプリケーションが大きい場合 (あるいは、サイズが増加していく場合) は、この時間がかなりの違いとなって現れることもあります。

ここに、お客様のサンプルが2つあります。1つは、非常に頻繁 (数分おき、あるいは文書が保存または変更されるたび) に実行されるスケジュール済みエージェントです。このエージェントはそれぞれの新規文書にアクセスし、検索条件を取得し、その条件に基づいて検索を実行します。たとえば、10個の新規文書が処理されると検索が10回行われ、100個の新規文書が処理されると検索が100回行われます。このエージェントで、文書コレクションを取得するたびに0.5秒削減できると、実際に削減される時間はその10倍または100倍になり、エージェントが頻繁に実行される場合は、さらに削減の度合いが倍加されます。このように、トラフィックの量が多い時間帯に、1時間あたり何分も簡単に削減できれば、これは大きな意味を持ちます。もう1つのサンプルは、このコードを実行するPostOpenイベントまたはQuerySaveイベントを持つ主要フォームです。1時間あたり数百回 (または、それ以上) の編集が行われる場合は、この0.5秒の削減が何倍にもなり、かなりの削減量となります。

各方法の長所と短所

私たちがお客様や同僚に、なぜ一部の方法が別の方法よりも速いのか、または使いやすいのかを説明するときに、「一方では・・・」、「もう一方では・・・」という活発な議論の形式を用いることがよくあります。これらの議論を深めるほど、問題点が明らかになっていきます。この記事でも同様の手法を用いて、神話の中からPrometheus (「Pro」と表記します) と疑い深い同僚のConnie (同様に「Con」と表記します) を登場させて、議論の形式で説明を進めましょう。

Prometheus:view.GetAllDocumentsByKeyはたいへん速いようです。私はできるだけこの方法を使用しようと思います。

Connie:確かにいいかもしれませんが、Lotus Dominoディレクトリでデータを検索するときはどうしますか。そこに新しいビューを作成する権限は簡単に得られないのでは。

Pro:よい指摘です。では、検索データベースを制御できるアプリケーションで、この方法を使用します。

Con:そうですか。データベース内で10個のビューを作成することになりますが、それでもよい方法ですか。ビューの索引を追加することも、検討しなければなりません。

Pro:それは面倒な気がしますが、簡素化したビューを作成すると、UPDATEタスクが実行される15分ごとに、通常は100ミリ秒未満で索引が作成されます。検索で必要な場合は、もう少し時間がかかります。もちろん、数分ごとに数百ミリ秒を費やすことは可能でしょう。

Con:これらのビューをどうやって簡素化しますか。難しくありませんか。維持にかなりの手間が掛かかるのでは。

Pro:まったく心配ありません。検索ビューを簡素化するには、まず、選択条件をできるだけ洗練されたものにします。これによってビューの索引サイズが減るため、索引の更新時間と検索の実行時間が短縮されます。次に、このビューに対してどのように検索するのかを考えます。すべての文書を取得する場合は、"1"の式を持つソート済みの列を1つ使用すればよいでしょう。ビュー内のすべての文書を取得することは簡単です。情報を含む多数の異なるフィールドが必要な場合は、これらのデータを連結する2番目の列を作成し、1回の検索で見つけられるようにします。結果的に同じデータが得られるにしても、複数回の検索よりも検索が速くなるでしょう。

Con:なるほど、この方法は良さそうですね。しかし、db.ftsearchも非常に速いという説明でしたが、私はこのメソッドを使用できるかどうかわかりません。このメソッドには、多くの基盤が必要な気がします。

Pro:確かに、db.ftsearchをコード内で適切に使用するには、全文索引を維持し、Domino Serverの設定に「FT_MAX_SEARCH_RESULTS=n」が含まれることを確認する必要があります。この場合のnは、コードに返す文書コレクションの最大サイズよりも大きな数に設定します。この設定がないと、文書数は5,000までに制限されます。

Con:それに、もし全文索引が十分に速く更新されない場合はどうなりますか。

Pro:その場合は、索引を更新するdb.UpdateFTIndexをコードに追加できます。

Con:私のテストによると、この処理にはかなり時間がかかる可能性があり、そもそもdb.ftsearchを使用することによるパフォーマンス面での利点がなくなってしまいます。また、全文索引がこれまでに作成されていなかったらどうなるのでしょうか。

Pro:データベース内の文書数が5,000未満の場合は、その場で一時的な全文索引が作成されます。

Con:2つの問題点があります。まず、一時的な全文索引はコードの実行後に破棄されるため、あまり効率がよくありません。次に、5,000文書は、上限のしきい値としては高くありません。私の組織では、一部のメール・ファイルだけがあてはまりそうです。データベース内に5,000を超える文書があるとどうなりますか。

Pro:その場合は、db.UpdateFTIndex (True) を使用すると、永続的な全文索引が作成されます。

Con:なるほど。しかし、大きなデータベースで全文索引を作成するのは、非常に時間がかかる可能性があります。また、全文索引はデータベースがコードに対してローカルにあるときにのみ作成されます。つまり、コードが実行されているのと同じサーバー上という意味です。

Pro:そのとおりです。幸いにも、Lotus Notes/Domino 7には、改善されたコンソール・ロギングやLotus Dominoドメインモニター (DDM) を使用する機能があり、全文索引を持たないデータベースに対するftsearchメソッドの使用などの問題を詳細にトラッキングできます。コンソール・ログに表示される可能性があるいくつかのメッセージを以下に示します。これらのメッセージは非常に明快であることがわかります。

Agent Manager: Full text operations on database 'xyz.nsf' which is not full text indexed.
This is extremely inefficient.
mm/dd/yyyy 04:04:34 PM Full Text message: 
index of 10000 documents exceeds limit (5000), aborting:
Maximum allowable documents exceeded for a temporary full text index

Con:view.ftsearch、view.GetAllEntriesByKey、db.searchは、あまり積極的に取り上げられていません。私には、その理由がわかる気がします。最初の2つは一部の条件では速いのですが、検索データが降順で索引付けされているビューでは、処理が非常に遅くなります。また、db.searchは、小さい文書コレクションでは、非常に効率が悪くなる傾向があります。

Pro:指摘された点は、すべてそのとおりです。しかし、db.searchは時刻/日付が影響する検索では非常に効率的です。たとえば、時刻/日付の式を持つビューを作成したくない場合や、db.ftsearchメソッドを使用するためだけに全文索引を維持したくない場合などです。また、自分の制御下にないデータベースを検索する際に、データベースの全文索引がまだ作成されていない場合は、db.searchが、文書コレクションを取得する唯一の方法となることがあります。

いくつかのグラフを使用して、先ほどProが指摘したポイントを定量化してみましょう。これらのグラフは、文書コレクションを単に取得するためにかかった時間を示します。取得した文書に対しては、読み出しおよび書き込みはまったく行っていません。これは、私たちのテスト環境でテスト・アプリケーションを用いて測定した結果なので、数値については参考程度にお考えください。しかし、それぞれの方法どうしの関係は、どの環境でも同じようになるはずです。

図1では、db.ftsearchとview.GetAllDocumentsByKeyはほとんど区別が付きません。どちらも、ベスト・パフォーマンスを達成しています。この2つは同率で首位といえます。これに僅差で続く第3位はview.GetAllEntriesByKeyです。view.ftsearchは、始めは非常に優れたパフォーマンスを示しますが、文書数が40を超えると、パフォーマンスが急激に低下します。

図1.文書コレクション、最適化されたビュー (100文書まで)
図1.文書コレクション、最適化されたビュー (100文書まで)

図2では、文書数が増えるほど db.searchのパフォーマンスが良くなっています。これは図 1 との唯一の違いで、注目に値します。データベース内の約5〜10%の文書数に対し、db.searchは前の2つと同じぐらい速くなることがわかりました。図1で示されるように、view.ftsearchは、文書コレクションのサイズが増えるほど速度が低下します。

図2.文書コレクション、最適化されたビュー (100〜1,000文書)
図2.文書コレクション、最適化されたビュー (100〜1,000文書)

図3では、結果を先頭に表示するようにビューが最適化されていません。これは、少しの文書だけのコレクションを得る場合、私たちのテスト環境では、検索ビューでこれらの文書を昇順または降順に配置することで、結果を意図的に変えられることを意味します。図1と2では、これらの文書はビューの先頭に並ぶ傾向にありましたが、図3では、これらの文書はビューの一番下にあります。3つの方法 (db.search、db.ftsearch、および view.GetAllDocumentsByKey) にとって、これは意味のないことです。しかし、view.ftsearchとview.GetAllEntriesByKeyにとっては、パフォーマンスの観点から、この違いは致命的です。図2と3では、縮尺を変更する必要があります。図1ではY軸は1秒までなのに対し、6秒まで必要です。

図3.文書コレクション、最適化されていないビュー
図3.文書コレクション、最適化されていないビュー

まとめ

可能である限り、文書コレクションの取得にはview.GetAllDocumentsByKeyを使用してください。この方法に加え、できる限り小さくかつ効率的になるよう検索ビューを簡素化します。この方法のヒントを第2部で説明します。

リッチ・テキスト・フィールドを検索する場合、またはデータベースの全文索引がすでに作成されている場合、db.ftsearchは優れたパフォーマンスを持ち、考慮に値します。文書数の制限によってデータの整合性を失わないよう保証するには、結果を5,000文書までにするか、Notes.iniパラメーター「FT_MAX_SEARCH_RESULTS=n」(nは返される最大文書数) を使用する必要があります。

これで、Lotus Notes/Domino 7アプリケーションのパフォーマンスに関する解説の第1部を終了します。第2部では、高いパフォーマンスを示すビューを作成する方法について解説します。第2部でお会いしましょう。

参考文献

学ぶために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Lotus
ArticleID=337701
ArticleTitle=Lotus Notes/Domino 7 アプリケーションのパフォーマンス: 第1部:データベース・プロパティーと文書コレクション
publish-date=01312006