階層型DBMSの極意:論理レコード長と物理ブロック長の物理調停術
ヘッダーアーキテクトの私だ。今日のコードレビュー、あるいは基本設計レビューで、また「なんとなく」でセグメント長を切っているジュニアの設計書を見かけた。
「なぜ、この論理レコード長(Logical Record Length)にしたのか?」
この問いに対して、「将来の拡張性を考慮して少し大きめに…」などという甘ったれた返答をするようでは、我がチームのメインフレーム/レガシー基盤のパフォーマンスは一瞬で崩壊する。現代のクラウドネイティブな世界から見れば化石のように扱われる階層型DBMS(IBM IMSなど)だが、その根底にある「ハードウェアの物理特性とデータ構造の完全な同期」という思想は、超高負荷な現代の分散ストレージ設計においてもそのまま通用する不変の真理だ。
今日は、階層型DBMSにおける論理レコード長と物理ブロック長の最適化について、妥協なき実務の知見を授けよう。
—
1. 階層型DBMSにおける「物理」と「論理」の乖離を断つ
リレーショナルデータベース(RDBMS)であれば、正規化されたテーブルとストレージエンジン(InnoDBなど)のページサイズ(通常16KB)の間には、オプティマイザとバッファプールという分厚い抽象化レイヤーが存在する。
しかし、階層型DBMS(IMS DBのHDAM/HIDAMなど)は違う。
親セグメント(Segment)と子セグメントがポインタチェーンで物理的に隣接、あるいは直結して配置される。ここで論理レコード(物理的にはセグメントの集合体、あるいはROOTを中心としたツリー構造のまとまり)のサイズと、OS/ストレージの物理ブロックサイズ(あるいはCI:Control Interval)の整合性が狂った瞬間、I/O効率は劇的に悪化する。
最悪のアンチパターン:スパンニング(Spanning)の発生
論理レコード長が物理ブロック長を超過したとき、OSやアクセス मेथडはデータを分割して複数ブロックに書き込む(あるいはポインタを飛ばす)。これがスパンニングだ。
1つの論理レコードを読むために、ディスクヘッドが(あるいはSSDのコントローラが)複数回のI/O発行を余儀なくされる。この「無駄なディスク回転待ち/追加I/O」こそが、バッチ処理を朝まで終わらせない元凶なのだ。
—
2. スキーマ定義(DDL/DBD)におけるサイズ設計の実際
IMS DBを例に、DBD(Database Definition)における物理ブロックサイズ(BLKSZ)と論理レコード長(LRECL)のチューニング例を見ていこう。
————————————————————–
- データベース記述 (DBD) のサンプル定義
————————————————————–
DBD NAME=CUSTDB,ACCESS=HDAM,RMNAME=(DFSHDC40,100,500)
- 物理ブロックサイズ (BLOCK) はストレージの最適サイズに合わせる
- ここでは現代的なSSD/SANの物理セクタ/Eraseブロックを意識し 4096バイト とする
DATASET DD1=CUSTD01,DEVICE=3390,BLOCK=4096,OTRK=5
- ルートセグメント:顧客マスタ (固定長 200バイト)
SEGM NAME=CUSTSEG,PARENT=0,BYTES=200,PTR=T
FIELD NAME=(CUSTID,SEQ,U),START=1,BYTES=10,TYPE=C
FIELD NAME=CUSTNAME,START=11,BYTES=50,TYPE=C
FIELD NAME=CUSTINFO,START=61,BYTES=140,TYPE=C
- 子セグメント:注文履歴 (可変長 最大 800バイト)
SEGM NAME=ORDSEG,PARENT=CUSTSEG,BYTES=(800,50),PTR=L
FIELD NAME=(ORDID,SEQ,U),START=1,BYTES=12,TYPE=C
FIELD NAME=ORDDATE,START=13,BYTES=8,TYPE=C
FIELD NAME=ORDMETH,START=21,BYTES=779,TYPE=C
この設計の急所
1. `BLOCK=4096` の選定:
物理的なブロック(あるいはCI)サイズをストレージのI/O単位(例: 4KBページ)の倍数、あるいは完全に一致させている。これにより、物理I/Oとバッファキャッシュのヒット率が最大化する。
2. 子セグメントの可変長指定 `BYTES=(800, 50)`:
最大長800バイト、平均長50バイトとして定義されている。ここで重要なのは、「1つの物理ブロック(4096バイト)の中に、親と頻繁にアクセスされる子セグメント群が何件収まるか」という算数だ。
—
3. 最適化の数式:パッキングファクター(Packing Factor)の極意
レビューの際、私は開発者に必ず次の計算をさせる。
$$\text{物理ブロック利用効率} = \frac{\sum (セグメント実効長 + プレフィックス制御情報)}{\text{物理ブロック長 (BLKSZ)}}$$
もし、親セグメント+代表的な子セグメント群の合計サイズが物理ブロック長を僅かに超過(例えば、4100バイト)していた場合、何が起きるか?
たった4バイトオーバーしただけで、2つ目の物理ブロックがアロケートされ、50%以上の物理領域が無駄(断片化:Fragmentation)になる。
チューニングの鉄則
- ブロック境界への収容(Fit to Block):
頻繁に一括取得(Get Unique / Get Next)する一連の階層パス(Root $\to$ Child 1 $\to$ Child 2)が、単一の物理ブロック内に完全に収まる(Clustered)ようにLRECLとセグメント長を調整しろ。
- プレフィックスのオーバーヘッドを忘れるな:
階層型DBMSでは、ポインタ(物理アドレスまたはRBA)を維持するために、各セグメントの先頭にプレフィックス(通常、数バイトから数十バイト)が付加される。これを計算に入れずに「フィールド長の合計だけで設計しました」などと言おうものなら、即座に差し戻しだ。
—
4. パフォーマンス上の注意点と実務の現場からの警告
最後に、実務で数千万件クラスの階層型DBを運用する上で、絶対に踏んではいけない地雷を共有しておく。
1. 「大きすぎるブロック」の罠
「I/O回数を減らすためにブロックサイズを32KBや64KBにしよう」という短絡的な意見が出る。しかし、これはバッファプールのコンテンション(競合)を引き起こす。単一レコードの更新であっても、巨大なブロック単位で排他制御(Latching)がかかるため、並行処理性能(Concurrency)が致命的に低下する。「1アクセスあたりに必要な最小限の塊」を攻めろ。
2. 動的な断片化(Database Degradation)の観測
可変長セグメントの挿入・削除が繰り返されると、物理ブロック内でFree Space(空き領域)の断片化が起きる。定期的な再編成(Reorganization:IMSでいうDFU/HD Unload/Reload)のスケジュールを設計に組み込んでいないシステムは、実稼働半年で確実に性能が劣化する。設計段階から「いつ、どうやって再編成するのか」を語れ。
—
結びにかえて
階層型DBMSの設計は、モダンなORMが隠蔽してくれた「ハードウェアとデータの物理的結合」を、エンジニアが自らの手で美しく調停する芸術だ。
論理レコード長と物理ブロック長の整合性を極限まで突き詰めたシステムは、驚異的なスループットと、無駄なリソースを一切消費しない圧倒的なエレガンスをまとって稼働する。
次の設計レビューでは、ただ動くだけのコードではなく、ストレージの鼓動を感じさせるような美しい物理設計を見せてほしい。期待している。
コメント