
本記事は、ノードの配列とデータ量の関係について解説します。
Q. ノードの順番を変えるとデータ量は変わるの?
A. 変わります。
「えっ、本当に!?」
と思われた方は、ぜひこの記事を最後までご覧ください。
きっと、あなたの認識が少しだけ変わるはずです。
データ・ブロックの中身
管理ポータル画面を開きグローバルを表示すると、下記の様に見慣れた構成で表示されます。
今更ですが、表示の構成としては「グローバルの名前」「各ノードの値」「各ノードに対するデータ」の3要素になります。
また、ノードが自動でソートされているのも、お馴染みですね。

ただし、データ・ブロックに格納される値は異なります。
では、データ・ブロックにはどのように格納されているのでしょうか。
データ・ブロックには、下記赤枠内にある「2回目以降のグローバル名」と「重複しているノード」が省略して格納されます。
下記の例では、赤枠の項目になります。

つまり、選択性(Selectivity)の高いノードと、選択性の低いノードがある場合、選択性の高い順に並べた方が、省略できる値が増える為、全体のデータ量が小さくなります。
逆に、選択性の低い順に並べると省略できる項目が減るため、額面通りのデータ量になります。
仕様が分かったので、検証を行いましょう。
検証
下記2つのプロパティを持つデータ・クラスがあります。
Class developer.data.DataCheck Extends (%Persistent, %Populate)
{
Index idx On (sei, name);
Property sei As %String(POPSPEC = "ValueList("",藤原,近衛,九条"")");
Property name As %String(POPSPEC = "StringMin(30,30)");
}
Populate関数で10,000件のデータを作成します。
※Pupulateの詳細は下記記事を参照してください。
作成されたデータを確認すると下記になります。
プロパティ名 | 選択性値 | 選択性 | データ例 |
---|---|---|---|
sei | 33.3333% | 高い | 藤原 or 近衛 or 九条(3種のみ) |
name | 0.0100% | 低い | ランダムな文字列(ほぼ全てが不一致) |
データ量が変化を簡単に検証するには、インデックスの組み換えを行うと良いです。
インデックス「idx」を選択性の異なる2つのプロパティの組み合わせで検証します。
下記2パターンを作成し、そのデータ量を測定してみましょう。
- Index idx On (sei, name); // 選択性が高い -> 低いの組み合わせ
- Index idx On (name, sei); // 選択性が低い -> 高いの組み合わせ
データ量の比較
データ量の比較の比較を行うのであれば、^%GSIZEを使用します。
※詳細は下記記事を参照してください。
今回は、グローバル「^developer.data.DataCheckI」を詳細モードで確認します。
zn "%SYS"
%SYS>d ^%GSIZE
Directory name: d:\iris\mgr\ => D:\IRISDB\SAMPLE-DATA
All Globals? No => No
Global ^developer.data.DataCheckI
Global ^
1 global selected from 89 available globals.
Show details?? No => yes
Device:
Right margin: 80 =>
結果を比較します。
項目 | ブロック数 | データ量(バイト) | Packing | Contig. |
---|---|---|---|---|
sei, nameの組み合わせ | 62 | 370,576 | 73% | 2 |
name, seiの組み合わせ | 78 | 445,436 | 70% | 1 |
ブロック数では16ブロック、バイト数では73kbの差が出ました。
※充填率の差に関しては、今回の検証対象外とさせて下さい。
この差は先ほど記述した通り、「グローバル名」・「藤原/近衛/九条の各重複ノード」が省略して格納された事によります。
とは言え、インデックスのノードの組み合わせは、参照する項目にも依存します。
検索する項目、選択性の高/低をよく検討しつつ、適切にインデックスを組めれば良いですね。
ノードの配置順でデータ量が変わる事は確認しました。
では、ループの速度はどうでしょう・・・?
次は、ループ速度を検証してみたいと思います。
ループ速度を検証する
速度差を検証するため、レコード数を増やしてループ速度を検証してみたいと思います。
下記簡単な関数を作成して、検証してみたいと思います。
ClassMethod loop()
{
s start = $zh
s (key1, key2) = ""
f {
s key1 = $o(^developer.data.DataCheckI("idx", key1))
q:key1=""
f {
s key2 = $o(^developer.data.DataCheckI("idx", key1, key2))
q:key2=""
}
}
w $zh - start
}
【実行結果】
sei, nameの組み合わせ:0.358816秒
name, seiの組み合わせ:0.636474秒
選択性の高い->低いの組み合わせの方が、ループ速度が速い結果となりました。
この差は、なぜ生まれるのでしょうか?
各ブロックの参照回数を比較しつつ確ししてみます。
【Index sei, nameの組み合わせ】
処理 | 時間 | GloRef | Disc Bpn | Disc Data | Buf Dir | Buf Data |
---|---|---|---|---|---|---|
s key1 = $o(^[I](“idx”, key1)) | 0.013104 | 4 | 1 | 1 | 1 | 0 |
s key2 = $o(^[I](“idx”, key1, key2)) | 0.470166 | 100003 | 0 | 624 | 0 | 1 |
Disc=ディスクアクセス, Buf=グローバル・バッファ
Dir=ディレクトリ・ブロック, Bpn=下部ポインタ・ブロック, Data=データ・ブロック
【Index name, seiの組み合わせ】
処理 | 時間 | GloRef | Disc Bpn | Disc Data | Buf Dir | Buf Data |
---|---|---|---|---|---|---|
s key1 = $o(^[I](“idx”, key1)) | 0.486492 | 100001 | 1 | 741 | 1 | 0 |
s key2 = $o(^[I](“idx”, key1, key2)) | 0.325522 | 200000 | 0 | 0 | 0 | 1 |
両者の比較を行うと、下記が言えると考えます。
ループ数の差に関しては、割とイメージしやすいです。
上位ノードの数が多いと、それだけループ数も増えますね。
まとめ
これまでの結果をまとめると下記になります。
ただしノードの組み方は、そのグローバルの用途に沿って組み上げるのが第一優先ではあります。
どの順番でも問題ない場合に限り、本記事の内容を参考にしてみて下さい。
以上、ノードの並び順と [データ量・ループ速度] の関係について解説致しました。
本記事が、皆さまの実務や学びの中で、少しでもお役に立てれば幸いです。