階層型DBMSの真価を解き明かす:HIDAM(階層索引直接アクセス手法)の内部構造と高倍率性能設計
現代のWebエンジニアやクラウドアーキテクトは、「データベース」と聞くと即座にRDBのB-Treeインデックスや、NoSQLのLSM-tree、ドキュメントストアを思い浮かべるだろう。SQLを書けば最適化クエリエンジンが裏側でよしなに処理してくれる時代だ。
だが、極限のIOPSと確定的な低レイテンシが求められるミッションクリティカルな巨大基幹システムにおいて、真の牙城を誇り続けているのは階層型DBMS(Hierarchical DBMS)である。
今回は、階層型DBMSにおけるアクセス手法の最高峰の一つであるHIDAM(Hierarchical Indexed Direct Access Method:階層索引直接アクセス手法)について解体する。一般的なリファレンスの表面的な解説は一切削ぎ落とし、ハードウェアのシーク、データセット構成、ポインタチェーン、そしてDBD(Database Description)の設計戦略まで、実務の設計レビューで即座に役立つ「本物の技術」を伝授する。
—
1. なぜ今、HIDAMなのか?:アクセス手法の進化論
階層型DBMS(代表例:IBM IMS DB)におけるデータアクセス手法は、大きく分けて「順次アクセス(HSAM/HISAM)」と「直接アクセス(HDAM/HIDAM)」に大別される。
| アクセス手法 | ルート検索方式 | 子セグメント検索方式 | 順序性維持(Scan) | 挿入・削除性能 |
| :— | :— | :— | :— | :— |
| HSAM | 物理的順次 | 物理的順次 | 完全維持 | 不可(再編成のみ) |
| HISAM | インデックス(VSAM KSDS) | 物理的順次(一部オーバーフロー) | 維持 | 低い(再配置オーバーヘッド大) |
| HDAM | ランダマイジング(ハッシュ) | 直結ポインタ | 不可(キー順走査不可) | 非常に高い |
| HIDAM | インデックス(VSAM KSDS) | 直結ポインタ | 完全維持 | 高水準(バランス型) |
設計レビューで「なぜHDAMではなくHIDAMなのか?」と問われたとき、君は即座に答えられなければならない。
HDAMはハッシュ関数を用いるため、ルートセグメントへのピンポイントアクセスは最速(1 IO)だが、キーの範囲検索(レンジスキャン)やキー順の報告書出力が壊滅的だ。
一方でHIDAMは、「ルートセグメントへのアクセスはVSAM KSDSによるインデックス検索」を行い、「階層内の走査および同一セグメントの走査は物理ポインタダイレクト参照」を行う。
つまり、「キー順での範囲スキャン」と「ポインタによる超高速な階層ダイレクトアクセス」を高度に両立させた決定版アーキテクチャ、それがHIDAMなのだ。
—
2. HIDAMの二重データセット構造(Physical Architecture)
HIDAMの物理構造を理解せずして、堅牢なDB設計は不可能だ。HIDAMは内部的に2つの独立した物理データセットを組み合わせて1つの論理データベースを構築する。
【INDEX Dataset (VSAM KSDS)】 【DATA Dataset (OSAM or ESDS)】
+——————————-+ +———————————–+
| Index Segment | | Root Segment A |
| [ Root Key ] -> [ Direct PTR ]|—-+ | [ Prefix | Data Payload ] |
+——————————-+ | | | |
| Index Segment | +—->| +– Child PTR —> Child Segment|
| [ Root Key ] -> [ Direct PTR ]| | +– Twin PTR —> Root Seg B |
+——————————-+ +———————————–+
① INDEX データセット(VSAM KSDS)
- ルートセグメントのプライマリキー(Sequence Field)のみを保持する。
- ルートデータへの物理ポインタ(RBA: Relative Byte Address、または4バイトのダイレクトアドレス)を格納。
- アプリケーションがキー指定でルートを要求すると、まずこのKSDSがB-Tree検索され、一発でデータデータセット上の物理位置を特定する。
② DATA データセット(OSAM または VSAM ESDS)
- 実データ(ルートセグメントおよびすべての配下セグメント)が格納される。
- ここではセグメント同士が物理的な隣接関係ではなく、セグメントヘッダー(Prefix)に含まれる物理ポインタによって網の目のように結合されている。
—
3. 実務レベルのDBD(Database Description)定義
理論を頭に入れたところで、具体的なDDL(DBD定義)を見てみよう。
以下は、受注システムにおける「注文(ORDER)- 明細(ITEM)- 配送情報(DELIV)」の階層構造をモデル化した、本番運用に耐えうるHIDAMのDBD記述例だ。
データ用DBD: `ORDERDBD.dbd`
====================================================================
- DATABASE DEFINITION FOR ORDER MANAGEMENT (HIDAM DATA DATASET)
====================================================================
DBD NAME=ORDERDBD,ACCESS=(HIDAM,OSAM)
DATASET DD1=ORDDATDD,BLOCK=(4096),DEVICE=3390
——————————————————————–
- ROOT SEGMENT: ORDER (注文ルートセグメント)
——————————————————————–
SEGM NAME=ORDROOT,PARENT=0,BYTES=120, X
PTR=(TWINBWD,FIRST)
- PTR=(TWINBWD,FIRST):
- – TWINBWD: 双方向物理ツインポインタ(PTF/PTB)を生成。高速削除・逆順走査を可能にする。
- – FIRST: 子セグメントへの最初の物理ポインタ(PCF)を保持。
FIELD NAME=(ORDID,SEQ,U),BYTES=12,START=1,TYPE=C
FIELD NAME=ORDDATE,BYTES=8,START=13,TYPE=C
FIELD NAME=CUSTID,BYTES=10,START=21,TYPE=C
——————————————————————–
- CHILD SEGMENT: ITEM (注文明細 – 依存セグメント Level 2)
——————————————————————–
SEGM NAME=ORDITEM,PARENT=ORDROOT,BYTES=80, X
PTR=(TWIN,FIRST)
- PTR=(TWIN,FIRST):
- – TWIN: 単方向物理ツインポインタ(PTF)。メモリオーバーヘッドを削減。
- – FIRST: 孫セグメントへのポインタ。
FIELD NAME=(ITEMNO,SEQ,U),BYTES=4,START=1,TYPE=Z
FIELD NAME=PRDCODE,BYTES=15,START=5,TYPE=C
FIELD NAME=QTY,BYTES=4,START=20,TYPE=F
——————————————————————–
- CHILD SEGMENT: DELIV (配送情報 – 依存セグメント Level 2)
——————————————————————–
SEGM NAME=ORDDELV,PARENT=ORDROOT,BYTES=200, X
PTR=TWIN
FIELD NAME=(DELIVID,SEQ,U),BYTES=10,START=1,TYPE=C
FIELD NAME=STATUS,BYTES=1,START=11,TYPE=C
DBDGEN
FINISH
END
索引データセット用DBD: `ORDINDX.dbd`
====================================================================
- DATABASE DEFINITION FOR ORDER INDEX (HIDAM INDEX DATASET)
====================================================================
DBD NAME=ORDINDX,ACCESS=(INDEX,VSAM)
DATASET DD1=ORDINDDD
SEGM NAME=ORDXSEG,PARENT=0,BYTES=12
FIELD NAME=(ORDID,SEQ,U),BYTES=12,START=1,TYPE=C
- LCHILD: 物理ルートセグメントとのバインディング定義
LCHILD NAME=(ORDROOT,ORDERDBD),INDEX=ORDID
DBDGEN
FINISH
END
—
4. コード解説とポインタのトポロジー(Prefixの内部解剖)
上記のDBDで定義したデータが、物理ストレージ上でどのような構造を持っているか、プレフィックス(Prefix)レベルで徹底解説する。
セグメントがブロックに書き込まれる際、各セグメントの先頭にはPrefix(制御情報)が厳密なバイト数で付与される。
+————-+————–+——————+——————+———————–+
| Segment Code| Delete Flag | PTF Pointer | PTB Pointer | PCF Pointer (Child) | Data Payload …
| (1 Byte) | (1 Byte) | (4 Bytes Address)| (4 Bytes Address)| (4 Bytes Address) | …
+————-+————–+——————+——————+———————–+
|<------------------------------ Prefix Area --------------------------------------------->|
ポインタ種別の選定基準(設計レビューのチェックポイント)
1. PTF (Physical Twin Forward): 同一親を持つ同種セグメントの「次」を指すポインタ(4バイト)。
2. PTB (Physical Twin Backward): 同一セグメントの「前」を指すポインタ(4バイト)。
- `PTR=TWINBWD` を指定した場合のみ生成。
- レビュー指摘ポイント: 頻繁に `DLET`(削除)コールが発行されるルートセグメントには必須。ポインタの再構築(前後ノードの繋ぎ替え)において、双方向リスト構造でないと前のセグメントを探すためにルートチェーンを先頭から走査するハザード(O(N)の遅延)が発生する。
3. PCF (Physical Child First) / PCL (Physical Child Last): 親セグメントから子セグメントの先頭/末尾を指すポインタ。
- 子セグメントの末尾追加(`ISRT`)が大量に発生する場合は `PTR=(…,LAST)` も追加し、PCF/PCLの双方を保持させるべきだ。これがないと、末尾挿入のたびにツインチェーンを全走査することになる。
—
5. 現場のチーフアーキテクトが教える「性能限界突破とアンチパターン」
HIDAMは極めて強力だが、雑な設計をすると一瞬でディスクI/Oのボトルネックに陥る。実務で遭遇する代表的な問題と解決策を伝授する。
アンチパターン1: インデックスのホットスポット化とKSDSのCI Split
HIDAMのルート挿入は、まずINDEXデータセット(VSAM KSDS)にキーを追加し、次にDATAデータセットに実データを書き込む。
キーが連番(タイムスタンプやシーケンシャルID)の場合、KSDSの同一Control Interval (CI) に書き込みが集中し、CI Split(Control Interval Split)が多発する。
- 症状: 挿入パフォーマンスが指数関数的に低下し、VSAMのI/O待ちが発生。
- 処方箋:
1. KSDSの `FREESPACE(CI_percent, CA_percent)` を適切にチューニング(例: `FREESPACE(20 20)`)。
2. 可能であれば、キーの先頭にハッシュ値の一部や分散コードを付与し、KSDSの書き込み位置を物理的に分散させる。
アンチパターン2: 自由領域(Free Space)の枯渇によるデータ離散(ポインタの長距離ジャンプ)
DATAデータセット(OSAM)内のブロック領域に空きがない場合、DBMSは離れたブロックに新しい子セグメントを格納する。
これにより、ポインタを1つ手繰るたびに異なる物理ブロックへのディスクシークが発生(ポインタ・ロット現象)する。
[Block 100] ORDROOT A —> (Pointer Jumps 500 Blocks!) —> [Block 600] ORDITEM A-1
- 症状: 階層走査(`GNP`: Get Next in Parent コール)の応答時間が劇的に悪化。
- 処方箋:
- DBDの `DATASET` マクロで `FRSPC=(num_seg, pct)` を正しく設定せよ。
- 定期的なDB再編成(REORG: Unload / Reload)の実装。
HIDAMの最大のメリットは、再編成時にルートがキー順に整列し、配下の子セグメントが同一物理ブロック内(または近傍ブロック)に再配置される点だ。REORG直後のHIDAMのレスポンス速度はRDBの比ではない。
アンチパターン3: 無計画な `PTR=TWIN` によるメモリ/ディスクの浪費
すべてのセグメントに `TWINBWD` や `PCL` を安易に設定してはならない。ポインタ1つにつき4バイト消費する。
数億件規模のセグメントが存在する場合、ポインタ領域だけでギガバイト単位のストレージを無駄にし、1ブロックに収まるセグメント数が減るため、キャッシュ効率(Buffer Pool Hit Ratio)が急降下する。
- 原則:
- 削除頻度が低い依存セグメントは `PTR=TWIN`(単方向)で十分。
- 追記専用ログのような構造であれば `PTR=TWIN` で十分。
- 検索・削除がランダムに発生する主要ノードのみ `PTR=TWINBWD` を許可せよ。
—
6. まとめ:アーキテクトとしての設計指南
HIDAMの本質とは、「インデックスによる検索の確定性」と「直結ポインタによる参照の限界突破」のハイブリッドにある。
RDBのJOIN処理がネステッドループやハッシュJOINによってCPUとメモリを激しく消費するのに対し、HIDAMは設計者が意図した通りの物理ポインタを直接ジャンプするため、データ量が増加しても階層走査のオーダーは事実上 $O(1)$ に近いパフォーマンスを維持できる。
1. ルート検索はKSDSで安全に受ける。
2. 階層走査はポインタ構造(PTF/PTB/PCF/PCL)をワークロードに合わせて最小限かつ最適に設計する。
3. データセットの物理配置(Block Size, Free Space)とREORG運用を設計初期段階から組み込む。
これらを徹底できて初めて、何十年経っても劣化しない「伝説的なミッションクリティカルシステム」を構築することができる。安易な抽象化に逃げず、ストレージの1バイト、ポインタの4バイトに魂を込めよ。
コメント