【実務・中級編】 ブロックサイズ最適化 – 階層型DBMS

RDBMSの「オプティマイザ任せ」のクエリプランに慣れきったエンジニアが、階層型DBMS(例えばIMS/DB)の設計に足を踏み入れたとき、最初に直面する最大の壁――それが「物理設計の絶対性」だ。

階層型DBMSにおいて、データは「ポインタ(物理アドレスまたはオフセット)」によって物理的に連結されている。RDBMSのように「インデックスをスキャンして適当にページを読み込む」のではない。親から子、子から孫、あるいは同一親内の兄弟(ツイン)へと、ポインタを愚直に手繰り寄せていく。

このアーキテクチャにおいて、1回の物理I/Oでどれだけのセグメント(階層ノード)をメモリ上に引き込めるかは、システムの心臓鼓動数(スループット)そのものを決定する。そして、その成否を握るのが、物理デバイス(DASD)のトラック容量に基づいた「ブロックサイズの極限最適化」である。

今回は、現代のシステム開発でも未だミッションクリティカルな超高頻度トランザクションを支え続ける階層型DBMSにおいて、ディスクの物理特性から逆算して「最強のブロックサイズ」を導き出す思考プロセスを伝授する。

—

1. なぜ「ブロックサイズ」が階層型DBMSの生殺与奪の権を握るのか?

階層型DBMSの物理格納方式(HSAM、HISAM、HDAM、HIDAMなど)では、ディスク上のデータは「ブロック(VSAMにおいてはコントロール・インターバル:CI)」という単位で管理される。

RDBMSであれば、多少ブロックサイズ(ページサイズ)が不適切でも、SSDの圧倒的なランダムアクセス性能や、DBMSの洗練されたバッファキャッシュ機構が覆い隠してくれる。しかし、階層型DBMSが扱うのは、往々にしてミリ秒以下の応答速度と数万TPS(Transaction Per Second)が要求される極限のメインフレーム環境だ。

ここでブロックサイズ設計を誤ると、以下の致命的な現象が発生する。

  • 内部断片化(Slack Space)の増大: ディスクの物理トラックの境界線に対して、ブロックサイズが中途半端なサイズだと、トラック末尾に「使われないデッドスペース」が大量に発生する。これはストレージの無駄だけでなく、チャネル転送効率を劇的に低下させる。
  • I/Oの多重発生(I/O Bottleneck): 階層ツリーを深く探索する際、必要な子セグメントが同一ブロック内に収まっていない場合、ポインタを1つ進めるたびに物理I/Oが発生する。
  • バッファプールの汚染: ブロックサイズが無駄に大きいと、1レコード読み込むために不要なデータまで大量にメモリに載せることになり、限られたバッファプールが即座に食いつぶされる。

—

2. 物理デバイス(3390 DASD)の解剖学と「黄金のブロックサイズ」

現在でもエンタープライズ環境のデファクトスタンダードであるIBM 3390 DASD(Direct Storage Access Device)の物理構造をベースに、数学的に最適なブロックサイズを導き出そう。

3390の物理スペック

  • 1トラックあたりの最大容量: 56,664 バイト

ただし、ディスク上にデータを書き込む際、ブロックとブロックの間にはインターブロック・ギャップ(IBG)と呼ばれる物理的な隙間や、ハードウェア制御用のメタデータ領域が必要となる。そのため、1ブロックのサイズを大きくすればするほど、1トラックに格納できる実データの総量は増えるが、メモリ効率や排他制御(ロック)の粒度とのトレードオフが発生する。

1つのトラックをいくつかのブロックに均等分割する場合、オーバーヘッドを差し引いた「実際に利用可能な最大ブロックサイズ」は、以下の数式と物理仕様から厳格に決定される。

| 1トラックあたりのブロック数 (Blocking Factor) | キーなしLDS/OSAMにおける最大ブロックサイズ(バイト) | 空間利用効率 |
| :— | :— | :— |
| 1(フル・トラック) | 56,664 | 100% |
| 2(ハーフ・トラック) | 27,998 | 98.8% |
| 3(サード・トラック) | 18,452 | 97.7% |
| 10 | 5,348 | 94.4% |
| 12 | 4,404 | 93.3% |
| 13 | 4,096 (標準的な4KB) | 94.0% |

伝説的な「ハーフ・トラック(27,998バイト)」の真実

実務において、大量のデータを高速にシーケンシャル処理、あるいは広範囲にランダムアクセスする際の絶対的な黄金律が、この「ハーフ・トラック(27,998バイト)」、またはVSAMのCIサイズとして適合させた「26,624バイト(26KB)」や「28,672バイト(28KB)」である。

なぜフル・トラック(56,664バイト)にしないのか?
理由は簡単だ。56KBという巨大なブロックを1回I/Oするオーバーヘッドと、それを載せるメインメモリ(31ビットアドレス空間の仮想ストレージ、あるいは64ビットのバッファプール)の消費量が、パフォーマンスの分岐点(Diminishing Returns)を超えてしまうからだ。ハーフ・トラックは、「I/O回数の削減」と「メモリ消費・排他制御の局所性」のバランスが極限状態で調和するポイントなのだ。

—

3. 【実践】DBD(データ構造定義)と物理パラメータの設定

では、具体的なスキーマ定義(DBD: Database Description)のコードを見ながら、この設計思想をどう落とし込むか解説する。

以下は、OSAM(Operating System Access Method)を使用したHDAM(階層直接アクセス法)データベースの定義例だ。

-asm

  • DATABASE DESCRIPTION (DBD) FOR HIGH-PERFORMANCE DB


DBD NAME=CUSTDB, +
ACCESS=(HDAM,VSAM) HDAM/VSAMハイブリッド構成

———————————————————————

  • DATASET定義: ここで物理的なブロックサイズ(またはCIサイズ)を指定する

———————————————————————
DATASET DD1=CUSTDD1, +
DEVICE=3390, +
BLOCK=(27998,27998) ハーフ・トラック(27,998)を明示指定!

  • ▲ ここでデバイス特性(3390)に最適化したブロックサイズを設定する。
  • ▲ VSAMの場合は、DEFINE CLUSTERのCISZ(Control Interval Size)と完全に一致させる。

———————————————————————

  • セグメント定義(Root / Child)

———————————————————————
SEGM NAME=CUSTOMER, +
PARENT=0, +
BYTES=512 ルートセグメント(512バイト)

LCHILD NAME=(CUSTXDF,CUSTINDX),INDEX=CUSTXREF

FIELD NAME=(CUSTID,SEQ,U),BYTES=10,START=1,TYPE=C

SEGM NAME=ORDER, +
PARENT=CUSTOMER, +
BYTES=128, 子セグメント:注文情報(128バイト)+
PTR=(T) フィジカル・ツイン・フォワード(PTF)

FIELD NAME=(ORDERID,SEQ,U),BYTES=12,START=1,TYPE=C

DBDGEN
FINISH
END

VSAM IDCAMSによる物理クラスター定義(JCL例)

VSAMデータセットとして定義する場合、JCL(Job Control Language)およびIDCAMSユーティリティでの `CONTROLINTERVALSIZE`(CISZ)の設定が、上記のDBD設計と完全に同期していなければならない。

//DEFINE EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=
//SYSIN DD
DEFINE CLUSTER –
(NAME(PROD.CUSTDB.DATA) –
TRK(500 50) –
SHAREOPTIONS(3 3) –
REUSE) –
DATA –
(NAME(PROD.CUSTDB.DATA.DATA) –
KEYS(10 0) –
RECORDSIZE(512 27998) – / LRECLの最小と最大 /
CISZ(28672)) / 3390に最適化したハーフ・トラック近似値 (28KB) /
/

※注: VSAMのCIサイズは2048の倍数(8192バイト以上の場合)にする必要があるため、物理的な27,998バイトに最も近く、かつ3390のトラック効率を落とさない「28,672バイト(28KB)」を選択している。これにより、1トラックあたり2個のCIが極めて高い充填率で格納される。

—

4. パフォーマンスを極限まで絞り出すための「3つの設計パターン」

ブロックサイズを決定する際、単に「ハーフ・トラックにすれば良い」というわけではない。階層型DBMSならではのデータの「形(トポロジー)」に合わせたチューニングパターンを頭に叩き込んでおけ。

パターンA:ランダムアクセス特化型(ツリーが浅く、Root直行が多い場合)

  • ユースケース: オンライントランザクション(OLTP)で、特定のRootセグメントとその直下の子セグメント1〜2個のみを高速に引き抜く。
  • 設計アプローチ:
  • ブロックサイズは小さめ(4,096バイト または 8,192バイト)に設定する。
  • 理由: 1回の物理I/Oのレスポンスタイム(転送時間)を極限まで短縮し、バッファキャッシュの回転率を最大化するため。巨大なブロックを読み込んでも、その大半が使われないのであれば、チャネル占有時間の無駄になる。

パターンB:シーケンシャル・バッチ混在型(子・孫セグメントが大量にぶら下がる場合)

  • ユースケース: 1つのRootに対して数千から数万の歴史データ(ツインセグメント)が数珠繋ぎになっており、夜間バッチでこれを一括走査する。
  • 設計アプローチ:
  • ブロックサイズは最大級(28,672バイト = ハーフ・トラック)を死守する。
  • 理由: 物理ポインタがブロックを跨ぐ回数を最小化するため。28KBのブロックであれば、128バイトの子セグメントが1ブロックに200個以上収まる。これにより、バッファヒット率は劇的に向上し、ディスクアームのシーク動作をほぼゼロに抑え込める。

パターンC:可変長セグメントと「スパン・レコード」の回避

階層型DBMSにおいて、セグメントの合計長がブロックサイズを超える、あるいはブロック境界を跨ぐ(Spanned Record)設定は絶対に避けよ。

  • ブロック境界を跨ぐレコードが発生すると、1レコードの読み込みに2回の物理I/Oが発生し、スループットは半分以下に落ちる。
  • 対策: `BLOCK` サイズは、想定される「Root + 主要な子セグメントの合計サイズ」の最低でも3〜5倍以上の余裕を持たせた値を設計値とすること。

—

チーフアーキテクトからの直言

「データベースチューニング」という言葉を聞くと、現代のエンジニアはすぐに「SQLの書き換え」や「インデックスの追加」、あるいは「メモリ(バッファ)の増設」を思い浮かべる。

しかし、階層型DBMSの世界、そして超巨大スケールのメインフレームシステムにおいて、最大のパフォーマンスを引き出すのは常に「物理構造との調和」だ。

ディスクドライブの円盤が、1分間に何回転し、その1トラックに物理的に何バイトの磁気データが書き込めるのか。その物理の限界から逆算して、DBDの1行、IDCAMSの1パラメータを決定する。この「泥臭くも極めてロジカルな設計」こそが、システムを何十年もノンストップで、かつ超高速に稼働させ続ける唯一の最適解なのだ。

君たちが設計しているそのデータベースは、物理デバイスの悲鳴を聞いていないか? もう一度、トラック幾何学の計算機を叩き直してほしい。

コメント

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