2025/12/30

Domino 体力測定:#1)ビュー操作 ① - 測定方法

先日の記事『訂正記事:GetAllEntriesByKey は本当に速いのか? - 再検証でわかった“逆転の真実”』 では、ビューを操作するメソッド GetAllDocumentsByKey と GetAllEntriesByKey をパフォーマンスの観点から比較しました。

その中で『GetAllDocumentsByKey が GetAllEntriesByKey より有利』と結論付けましたが、その要因としてストレージの I/O や CPU などの影響が考えられることに触れるにとどまり、具体的な数値までは示していませんでした。そのため「実際にどの程度の差があるのか?」という疑問を持たれた方もいるかと思います。

そこで、この新連載『Domino 体力測定』では、Notes/Domino の機能や性能、挙動などについて、スポーツテストのように測定し、記録していきます。検証は手元の PC を使用して行い、測定条件や環境についても可能な限り明記します。

ビジネスでの実運用環境、とくにクラウド環境や仮想環境では異なる結果となる可能性もありますが、基準となる情報があれば、別の環境であっても仮説を立てることができるかと思います。この記事が何らかの参考になれば幸いです。


ビュー操作の測定

最初の検証は、この連載のきっかけにもなった「ビューの検索や結果の取得のパフォーマンス」です。実験に使用するメソッドは、もちろん GetAllDocumentsByKey が GetAllEntriesByKey です。今回は測定準備として、テスト用 DB とテストデータ(文書)、測定項目と測定プログラム(関数)を紹介します。


テスト項目

まずは測定項目です。以前の記事とほぼ同じですが改めて掲載します。


検証項目 D)GetAllDocumentsByKey E)GetAllEntriesByKey
1 コレクション作成 GetAllDocumentsByKey で検索し、コレクションを取得GetAllEntriesByKey で検索し、コレクションを取得
2 エントリ取得 GetFirstDocument、GetNextDocument で文書を取得GetFirstEntry、GetNextEntry でエントリを取得
3 値の取得 文書から値を取得ColumnValues で値を取得
4 文書の取得 Document プロパティで文書を取得
5 文書から値の取得 文書から値を取得

測定項目は、検索方法のイニシャル(D または E)と検証番号の組み合わせて表現します。例えば、D1 は ”GetAllDocumentsByKey のコレクション作成” となります。

ビューを検索して値を取得する時間の比較であれば、D1 ~ D3 と E1 ~ E3 を比較します。ビューの列にないフィールド値を取得したりフィールド値を更新する場合には、文書が必要となります。このような操作では、D1 ~ D3 と E1, E2, E4, E5 を比較することになります。


テスト DB

検証に使用する DB にはノーツでは少し多めの 10 万文書を用意します。0 ~ 99999 の番号に対して、次のような文書を作成します。

各桁のフィールドやカテゴリの項目は、将来の測定で柔軟にテストできるようにあらかじめ用意しておきます。また、テキストフィールドには値取得用に 100 バイトの文字列を設定します。

Private Function xViewSearch_CreateTestData2(vndb As NotesDatabase)
   Dim l As Long
   Dim s As String
   Dim i As Integer
   Dim nd As NotesDocument

   For l = 0 To 99999    '10万件
      s = Format(l, "000000")

      Set nd = vndb.Createdocument()
      nd.Form = "fTest"

      '検索用の値
      For i = 1 To Len(s)
         Call nd.Replaceitemvalue("Digit_" & CStr(i), Mid(s, Len(s) - i + 1, 1))
         Call nd.Replaceitemvalue("Category_" & CStr(i), Left(s, i))
      Next

      '取得用の値
      s = Right("0000000000" & s, 10)    '10バイト
      s = s & s & s & s & s & s & s & s & s & s     '10 x 10 = 100バイト
      Call nd.Replaceitemvalue("Text", s)

      Call nd.Save(True, True)
   Next
End Function

検索用のビューには、2 列を作成します。1 列目は検索列で Category_3 をソートして配置、2 列目は値取得用の列で Text フィールドを配置します。

例えば、このビューで "012" で検索すると 1000 文書がヒットすることになります。


測定方法

実行時間の測定には Timer 関数を使用します(使い方については過去記事『実行時間の計測(Timer 関数)』を参照)。ただ、この関数は精度が 1/100 秒となっており、処理時間を測定するには粗すぎます。そこで、ループを使って繰り返し実行させて処理時間を稼ぎ、できる限り正確に測定することとします。

各検証項目(D1 ~ D3、E1 ~ E5)毎に測定関数を作成します。各関数のインターフェースは同じとします。

・ 引数

1 vnv NotesView 測定に使用するビュー
・Refresh メソッドで索引更新済み
・AutoUpdate は False
2viFm Integer 検索カテゴリ(開始値)
3viTo  Integer 検索カテゴリ(終了値)
4viLoop Integer コレクションから取得するエントリ数

引数の 2 ~ 4 はループ回数を調整するために使用します。

・ 戻り値

Double 実行時間(秒)


◇ 検証 D1

GetAllDocumentsByKey でビューを検索し、コレクションを取得する時間を測定します。viFm ~ viTo までを順に検索させ、毎回違うコレクションが返ってくるようにしています。

Private Function xTest_D1(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer

   'オブジェクト格納用配列
   Dim ndc() As NotesDocumentCollection
   ReDim ndc(viTo-viFm)

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo '範囲を順に検索
      '検証 ①:コレクションの取得
      Set ndc(iCD-viFm) = vnv.GetAllDocumentsByKey(Right("00" & CStr(iCD), 3), True)
   Next

   '計測時間
   xTest_D1 = Timer() - sgST
End Function


◇ 検証 D2

NotesDocumentCollection からエントリを取得する時間を測定します。

計測準備で、検索結果のコレクションを格納用配列 ndc() にあらかじめ取得しておきます。測定開始着、この格納用配列からコレクションにアクセスすることで、エントリ取得時間だけを測定するようにしています。

Private Function xTest_D2(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer
   Dim iLoop As Integer

   'オブジェクト格納用配列
   Dim ndc() As NotesDocumentCollection
   Dim nd() As NotesDocument
   ReDim ndc(viTo-viFm)
   ReDim nd(viTo-viFm, viLoop)

   '計測準備:測定されたくないオブジェクト取得
   For iCD = viFm To viTo    '範囲を順に検索
      '検証 ①:コレクションの取得
      Set ndc(iCD-viFm) = vnv.GetAllDocumentsByKey(Right("00" & CStr(iCD), 3), True)
   Next

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo    '範囲を順に処理
      '検証 ②:エントリの取得
      Set nd(iCD-viFm, 1) = ndc(iCD).GetFirstDocument()
      For iLoop = 2 To viLoop
         Set nd(iCD, iLoop) = ndc(iCD).GetNextDocument(nd(iCD, iLoop-1))
      Next
   Next

   '計測時間
   xTest_D2 = Timer() - sgST
End Function


◇ 検証 D3

NotesDocument から値の取得時間を測定します。

コレクションごとに viLoop 回取得させます。よって、格納用配列 nd は 2 次元で、測定時のループは 2 重となっています。

Private Function xTest_D3(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer
   Dim iLoop As Integer
   Dim s As String

   'オブジェクト格納用配列
   Dim ndc() As NotesDocumentCollection
   Dim nd() As NotesDocument
   ReDim ndc(viTo-viFm)
   ReDim nd(viTo-viFm, viLoop)

   '計測準備:測定されたくないオブジェクト取得
   For iCD = viFm To viTo    '範囲を順に検索
      '検証 ①:コレクションの取得
      Set ndc(iCD-viFm) = vnv.GetAllDocumentsByKey(Right("00" & CStr(iCD), 3), True)

      '検証 ②:エントリの取得
      Set nd(iCD-viFm, 1) = ndc(iCD).GetFirstDocument()
      For iLoop = 2 To viLoop
         Set nd(iCD, iLoop) = ndc(iCD).GetNextDocument(nd(iCD, iLoop-1))
      Next
   Next

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo    '範囲を順に処理
      For iLoop = 1 To viLoop
         '検証 ③:値の取得
         s = nd(iCD, iLoop).Text(0)
      Next
   Next

   '計測時間
   xTest_D3 = Timer() - sgST
End Function


◇ 検証 E1

GetAllEntriesByKey でビューを検索し、コレクションを取得する時間を測定します。D1 とはメソッドが違うだけで、構造は同様になります。

Private Function xTest_E1(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer

   'オブジェクト格納用配列
   Dim nvec() As NotesViewEntryCollection
   ReDim nvec(viTo-viFm)

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo    '範囲を順に検索
      '検証 ①:コレクションの取得
      Set nvec(iCD-viFm) = vnv.GetAllEntriesByKey(Right("00" & CStr(iCD), 3), True)
   Next

   '計測時間
   xTest_E1 = Timer() - sgST
End Function


◇ 検証 E2

NotesViewEntryCollection から NotesViewEntry オブジェクトを取得する時間を測定します。

Private Function xTest_E2(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer
   Dim iLoop As Integer

   'オブジェクト格納用配列
   Dim nvec() As NotesViewEntryCollection
   Dim nve() As NotesViewEntry
   ReDim nvec(viTo-viFm)
   ReDim nve(viTo-viFm, viLoop)

   '計測準備:測定されたくないオブジェクト取得
   For iCD = viFm To viTo    '範囲を順に検索
      '検証 ①:コレクションの取得
      Set nvec(iCD-viFm) = vnv.GetAllEntriesByKey(Right("00" & CStr(iCD), 3), True)
   Next

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo    '範囲を順に処理
      '検証 ②:エントリの取得
      Set nve(iCD, 1) = nvec(iCD).GetFirstEntry()
      For iLoop = 2 To viLoop
         Set nve(iCD, iLoop) = nvec(iCD).GetNextEntry(nve(iCD, iLoop-1))
      Next
   Next

   '計測時間
   xTest_E2 = Timer() - sgST
End Function


◇ 検証 E3

ColumnValues プロパティを使って、ビューから値を取得する時間の計測です。

Private Function xTest_E3(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer
   Dim iLoop As Integer
   Dim s As String

   'オブジェクト格納用配列
   Dim nvec() As NotesViewEntryCollection
   Dim nve() As NotesViewEntry
   ReDim nvec(viTo-viFm)
   ReDim nve(viTo-viFm, viLoop)

   '計測準備:測定されたくないオブジェクト取得
   For iCD = viFm To viTo    '範囲を順に検索
      '検証 ①:コレクションの取得
      Set nvec(iCD-viFm) = vnv.GetAllEntriesByKey(Right("00" & CStr(iCD), 3), True)

      '検証 ②:エントリの取得
      Set nve(iCD, 1) = nvec(iCD).GetFirstEntry()
      For iLoop = 2 To viLoop
         Set nve(iCD, iLoop) = nvec(iCD).GetNextEntry(nve(iCD, iLoop-1))
      Next
   Next

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo    '範囲を順に処理
      For iLoop = 1 To viLoop
         '検証 ③:値の取得
         s = nve(iCD, iLoop).ColumnValues(1)
      Next
   Next

   '計測時間
   xTest_E3 = Timer() - sgST
End Function


◇ 検証 E4

NotesViewEntry の Document プロパティで文書を取得する時間を測定します。

Private Function xTest_E4(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer
   Dim iLoop As Integer
   Dim s As String

   'オブジェクト格納用配列
   Dim nvec() As NotesViewEntryCollection
   Dim nve() As NotesViewEntry
   Dim nd() As NotesDocument
   ReDim nvec(viTo-viFm)
   ReDim nve(viTo-viFm, viLoop)
   ReDim nd(viTo-viFm, viLoop)

   '計測準備:測定されたくないオブジェクト取得
   For iCD = viFm To viTo    '範囲を順に検索
      '検証 ①:コレクションの取得
      Set nvec(iCD-viFm) = vnv.GetAllEntriesByKey(Right("00" & CStr(iCD), 3), True)

      '検証 ②:エントリの取得
      Set nve(iCD, 1) = nvec(iCD).GetFirstEntry()
      For iLoop = 2 To viLoop
         Set nve(iCD, iLoop) = nvec(iCD).GetNextEntry(nve(iCD, iLoop-1))
      Next
   Next

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo    '範囲を順に処理
      For iLoop = 1 To viLoop
         '検証 ④:文書の取得
         Set nd(iCD, iLoop) = nve(iCD, iLoop).Document
      Next
   Next

   '計測時間
   xTest_E4 = Timer() - sgST
End Function


◇ 検証 E5

NotesViewEntry から取得した NotesDocument 経由でフィールド値を取得する時間を計測します。D3 と比較すれば NotesDocument の取得方法で差があるのかが確認できます。 

Private Function xTest_E5(vnv As NotesView, ByVal viFm As Integer, ByVal viTo As Integer, ByVal viLoop As Integer) As Double
   Dim sgST As Single
   Dim iCD As Integer
   Dim iLoop As Integer
   Dim s As String

   'オブジェクト格納用配列
   Dim nvec() As NotesViewEntryCollection
   Dim nve() As NotesViewEntry
   Dim nd() As NotesDocument
   ReDim nvec(viTo-viFm)
   ReDim nve(viTo-viFm, viLoop)
   ReDim nd(viTo-viFm, viLoop)

   '計測準備:測定されたくないオブジェクト取得
   For iCD = viFm To viTo    '範囲を順に検索
      '検証 ①:コレクションの取得
      Set nvec(iCD-viFm) = vnv.GetAllEntriesByKey(Right("00" & CStr(iCD), 3), True)

      '検証 ②:エントリの取得
      Set nve(iCD, 1) = nvec(iCD).GetFirstEntry()
      For iLoop = 2 To viLoop
         Set nve(iCD, iLoop) = nvec(iCD).GetNextEntry(nve(iCD, iLoop-1))
      Next

      '検証 ④:文書の取得
      For iLoop = 1 To viLoop
         Set nd(iCD, iLoop) = nve(iCD, iLoop).Document
      Next
   Next

   '測定開始
   sgST = Timer()

   For iCD = viFm To viTo    '範囲を順に処理
      For iLoop = 1 To viLoop
         '検証 ⑤:値の取得
         s = nd(iCD, iLoop).Text(0)
      Next
   Next

   '計測時間
   xTest_E5 = Timer() - sgST
End Function


次回の予定

これで測定材料が整いました。これらを使ってビューの検索と値取得の性能調査を順次行います。次回は、GetAllDocumentsByKey と GetAllEntriesByKey 基本的な挙動を調査します。


Domino 体力測定


0 件のコメント:

コメントを投稿