【実務・中級編】 物理ストレージブロックとCI/CA – 階層型DBMS

階層型DBMSにおける物理ストレージ攻略:CI/CA(制御インターバル/制御エリア)の極限設計論

現代のRDBMSやNoSQLの抽象化されたストレージレイヤーに慣れきったエンジニアが、ミッションクリティカルな超大規模・高スループットシステムを扱う階層型DBMS(IBM IMS DB等)の物理設計に足を踏み入れると、ほぼ間違いなくパフォーマンスの壁にぶち当たる。

「インデックスを貼れば速くなる」という幻想はここには存在しない。階層型DBMSにおいて、パフォーマンスの9割は「データが物理ディスクのどのブロックに、どう詰め込まれているか」で決まる。

今回は、階層型DBMSの心臓部であるCI(Control Interval:制御インターバル)とCA(Control Area:制御エリア)の物理構造を解剖し、I/Oを極限まで削減するための物理DDL(DBD:Database Description)設計手法と、実務で絶対に避けるべきアンチパターンを伝授する。

—

1. 物理I/Oの最小単位:CIとCAの構造を解剖する

まず、抽象概念をすべて捨て、物理ディスク(DASD)上のバイト列としてストレージを捉え直してほしい。階層型DBMS(特にVSAM/OSAMを基盤とするモデル)では、データをCIとCAという階層的なブロック単位で管理する。

+———————————————————————–+
| Control Area (CA) |
| +—————————————————————–+ |
| | Control Interval (CI) #1 | |
| | +————+————+—————+—–+——+——+ | |
| | | Record 1 | Record 2 | Free Space… | RDF | RDF | CIDF | | |
| | +————+————+—————+—–+——+——+ | |
| +—————————————————————–+ |
| | Control Interval (CI) #2 | |
| | +————+—————————-+—–+——+——+ | |
| | | Record 3 | Free Space… | RDF | … | CIDF | | |
| | +————+—————————-+—–+——+——+ | |
| +—————————————————————–+ |
| | Sequence Set CI (Index CI for this CA) | |
| +—————————————————————–+ |
+———————————————————————–+

CI(Control Interval)とは

  • 物理I/Oの最小基本単位。 OSがディスクからメモリ(バッファプール)へ転送するデータの最小塊である。
  • 内部には「実際のデータレコード」「フリースペース(空き領域)」のほか、自身の制御情報であるCIDF(Control Interval Definition Field)と、各レコードの長さを保持するRDF(Record Definition Field)が末尾に配置される。
  • つまり、「CIサイズ = 実データ + フリースペース + 制御情報(CIDF/RDF)」となる。このバイト計算を誤ると、一発でオーバーフローを引き起こす。

CA(Control Area)とは

  • CIを一定数まとめた連続物理領域。 通常はトラックやシリンダといった物理ディスクの幾何学的単位にマッピングされる。
  • CAの重要な役割は「インデックスのローカリティ制御」だ。VSAM B-Treeの最下層インデックス(Sequence Set)は、1つのCA内のCI群と1対1で対応する。
  • 後述する「CI分割(CI Split)」や「CA分割(CA Split)」が発生した際、システム負荷が激変するバウンダリ(境界)として機能する。

—

2. 階層構造をCIにどう詰めるか:DBD(DDL)による物理定義

階層型DBMS(例:IMS DBのHDAM/HIDAMアクセス方式)において、ルートセグメントから子・孫セグメントへとツリーをたどる探索コストは、「階層パスが何つのCIをまたぐか」に完全に依存する。

親セグメントと子セグメントが同一CI内に収まっていれば、階層トラバースのI/Oコストは実質ゼロ(メモリ内ポインタ参照のみ)になる。これが階層型DBMSの極限の速さの秘密だ。

以下に、VSAM ESDS/KSDSをベースとした階層型データベース定義(DBD)の実体例を示す。

  • ===================================================================
  • IMS Database Description (DBD) Example
  • 顧客(CUST) – 注文(ORDER) – 明細(ITEM) の3階層モデルの物理最適化定義
  • ===================================================================

DBD NAME=SALEDB,ACCESS=(HIDAM,VSAM)

  • 物理データセット群の定義 (CI/CAサイズの決定)

DATASET DD1=SALEDD, X
DEVICE=3390, X
BLOCK=(4096), / CI Size: 4KB (4096 Bytes) / X
RECORD=(4080) / Logical Record Size /

  • 1. ルートセグメント: 顧客基本情報

SEGM NAME=CUSTSEGM,BYTES=200,PARENT=0
FIELD NAME=(CUSTID,SEQ,U),BYTES=10,START=1,TYPE=C

  • 2. 子セグメント: 注文情報 (1顧客あたり平均5件と想定)

SEGM NAME=ORDSEGM,BYTES=150,PARENT=CUSTSEGM
FIELD NAME=(ORDDATE,SEQ,M),BYTES=8,START=1,TYPE=C

  • 3. 孫セグメント: 注文明細 (1注文あたり平均4件と想定)

SEGM NAME=ITEMSEGM,BYTES=80,PARENT=ORDSEGM
FIELD NAME=(ITEMSEQ,SEQ,U),BYTES=4,START=1,TYPE=C

DBDGEN
FINISH
END

設計レビューでのツッコミポイント(数学的計算)

上記コードの `BLOCK=(4096)` の意図をロジカルに説明できるか?

  • 1ルート(CUST: 200B)
  • 5注文(ORDER: 150B × 5 = 750B)
  • 20明細(ITEM: 80B × 20 = 1,600B)
  • セグメントヘッダ・ポインタオーバーヘッド: 約10B/セグメント × 26 = 260B
  • 合計予想ツリーサイズ ≒ 2,810 Bytes

4096バイトのCIを設定することで、制御領域(CIDF/RDF: 約10〜20B)を差し引いた実効キャパシティ(約4070B)内に「1顧客のツリー全体(2,810B)」がすっぽり1つのCIに収まる。

もしCIサイズを2048バイトに日和(ひよ)れば、1顧客のデータを読むだけで物理I/Oが2回発生し、スループットは半減する。逆に8192バイトに無駄に広げれば、バッファキャッシュのhit率を低下させ、無駄なバス転送を生む。

—

3. 堅牢な設計パターン:ポインタ配置とフリースペース最適化

新規データの挿入(INSERT)や更新によるセグメント伸長が発生する稼働系システムにおいて、CI/CAを無破壊で維持するための2大パターンを提示する。

パターン1:階層パッキングと物理ポインタの同期設計

階層型DBMSでは、セグメント間を接続するポインタ構造(PTF: Physical Twin Forward, PTB: Physical Twin Backward, PP: Physical Parent)を選択できる。

  • 同一CI内にセグメントが収まる場合: ポインタの探索コストは極めて低い。
  • CIをまたぐ場合: ポインタを直接アドレス(RBA: Relative Byte Address)で保持するため、直列アクセス性能を維持するには物理配置の近接性が不可欠となる。

【鉄則】
子セグメントの挿入頻度が高い場合、DBDで `PTR=TWIN`(双方向ポインタ)を確保しつつ、後述するCI内フリースペース(FREESPACE)を意図的に残す設計を行わなければならない。

パターン2:CI/CAフリースペース戦略

VSAMデータセット作成(IDCAMS)において、空き領域をあらかじめ物理配置しておく。

/ IDCAMS DEFINE CLUSTER スクリプト抜粋 /
DEFINE CLUSTER ( –
NAME(DB.SALEDB.DATA) –
INDEXED –
KEYS(10 0) –
RECORDSIZE(4080 4080) –
CONTROLINTERVALSIZE(4096) –
FREESPACE(15 20) – / CIの15%、CAの20%を空き領域として保持 /
SHAREOPTIONS(3 3) –
)

  • FREESPACE(15 20) の意味:
  • CI FREESPACE (15%): 各CIの15%を空けて初期ロードする。ランダムな子セグメント追加(例:新しい注文明細の追加)が起きても、既存のCI内で吸収し、後述する「CI分割」を防止する。
  • CA FREESPACE (20%): CA内の全CIのうち20%を完全な「空きCI」として確保する。特定CIが溢れてCI分割が発生した際、同じCA内の空きCIへデータを退避させることで、「CA分割」を防止する。

—

4. パフォーマンスの破滅を招く物理アンチパターン

レビューで即却下すべき、致命的な物理設計のアンチパターンを3つ挙げる。

アンチパターン1:CI Split / CA Split の連鎖(分割ストーム)

フリースペースが枯渇した状態でINSERTが走ると何が起きるか。

1. CI Split: CI内にデータが入らないため、CI内の半分のデータを新しいCIへコピーする。この間、排他ロックがかかり、I/Oが2回増大する。
2. CA Split: 同一CA内に空きCIもない場合、CA全体(1シリンダ等)の半分をまるごと新しいCAへ引っ越す。

【CA Splitの悪夢】
1. 新しいCAをアロケート
2. 既存CAの半分のCIを新CAへコピー(大量ブロック Read/Write)
3. インデックス(Sequence Set)の再構築
4. 処理中、該当CA全体がロック ⇒ アプリケーション応答遅延(数秒レベルのスパイク)

対策: 運用モニタリングで `SPLIT-CI` および `SPLIT-CA` のカウントを監視すること。割れ始めたら即座にREORG(データベース再編成)を実行するか、FREESPACE設計を見直さなければならない。

アンチパターン2:DASDトラック境界との非整合(Track Unalignment)

物理ディスク(例:IBM 3390 DASD)の1トラックの容量は 56,664 Bytes である。
何も考えずに CI Size = 5000 Bytes などという中途半端な値を設定したらどうなるか?

  • $56,664 \div 5000 = 11$ CI/トラック (使用量: 55,000 Bytes)
  • 残り 1,664 Bytes がトラック末尾で物理的に捨てられる(トラック内ギャップ)。

最適値は、トラック容量を無駄なく割り切れるサイズ、すなわち 4096 (4KB), 8192 (8KB), 18432 (18KB), 27648 (27KB) などである。物理ハードウェアのジオメトリを無視したCI定義は、幾何学的な容量ロスと不要なシークタイムを生む。

アンチパターン3:バッファプールとCIサイズの不一致

DBMSの領域定義で `CI SIZE = 8192 (8KB)` と定義しているにもかかわらず、OS/DBMSのバッファプール初期化パラメータで `4KB Buffer Pool` しか大量割り当てしていないケース。

この場合、8KBのCIを読むために4KBバッファを跨ぎ処理するサブオプティマルなI/O構造になり、最悪の場合はデータベースのオープン時にエラーでアボンド(Abend)する。物理CIサイズとバッファプール(OSAM/VSAM Buffer pool)のページサイズは必ず1対1で適合させよ。

—

5. アーキテクトとしての結論

階層型DBMSにおけるパフォーマンスチューニングとは、SQLの実行計画を眺めることではない。「データアクセスのパターンに合わせて、1回の物理I/O(1 CI)で目的のセグメント群をいかに過不足なくメモリ上にロードするか」という物理パズルを解くことだ。

1. 業務要件からセグメントの出現頻度(カーディナリティ)を分析せよ。
2. 1ツリーあたりの物理バイト数を算出し、トラック境界に合致する最適なCIサイズを導け。
3. 更新特性(INSERT/UPDATE)に応じてFREESPACE(CI, CA)を適切に配置し、CI/CA Splitを阻止せよ。

抽象化に逃げてはならない。物理構造を制する者だけが、階層型DBMSの真のポテンシャル(数十万TPSに耐える超低レイテンシ)を引き出すことができるのだ。

コメント

タイトルとURLをコピーしました