階層型DBMSの「禁断の果実」:二次索引(Secondary Indexing)を完全制御する
階層型DBMS(IMS等)を「レガシーの遺物」と切り捨てるのは簡単だ。しかし、ポインタを辿る物理的な結合の速さを知る者にとって、それは依然として最強のデータアクセスエンジンの一つであることに変わりはない。
だが、階層型DBの弱点は明白だ。ルートから子へ、子から孫へと「ポインタを辿る」という構造上、非階層キーでの検索はフルスキャン(掃引)という死を意味する。
そこで登場するのが「二次索引(Secondary Indexing)」だ。今回は、この諸刃の剣をどう使いこなし、パフォーマンスを殺さずにシステムを設計するか、その極意を伝授する。
—
1. 二次索引の本質:インデックスという名の「別世界」
リレーショナルDBのインデックスとは異なり、階層型DBにおける二次索引は、「実データとは別の独立した階層構造を構築すること」に他ならない。
例えば、`顧客(Root) -> 注文(Child) -> 明細(Grandchild)` という構造があったとしよう。顧客番号(ルートキー)でアクセスするのは容易だが、「特定の製品コードを含む注文をすべて探せ」と言われた瞬間、物理ポインタは役に立たなくなる。
ここで二次索引を作成すると、DBMSは内部的に「製品コードをルートとした逆引き用の階層」を自動生成する。
なぜこれが「禁断の果実」なのか
二次索引は以下のコストを伴うからだ。
- 物理I/Oの増大: レコードの挿入・更新のたびに、インデックス側の階層も更新しなければならない。
- バッファプール汚染: インデックスの更新が頻発すれば、メインのデータ領域より先にインデックス領域のバッファが溢れる。
これを理解せず、安易に索引を増やすアーキテクトは二流だ。
—
2. 堅牢な設計パターン:疎結合と「インデックス・ルート」
二次索引を設計する際、最も避けるべきは「頻繁に更新されるフィールドへのインデックス付与」だ。
推奨設計:非揮発属性への適用
二次索引は、以下のような「検索の起点」となるが、更新頻度が極めて低い属性に絞るべきだ。
- 顧客のメールアドレス: 変更頻度が低い。
- 管理番号(ステータスコード): 検索条件として強力。
[設計上の鉄則]
・「更新頻度」と「検索頻度」のトレードオフをマトリクス化せよ。
・更新頻度が検索頻度を上回るなら、二次索引を捨てて「検索専用の別セグメント」を設計する方が遥かに安上がりだ。
—
3. パフォーマンスを殺さないための「ポインタ解決」の作法
実務で最も恐ろしいのは、二次索引経由でアクセスした際、「親セグメントの取得」に失敗してI/Oの嵐が起きることだ。
階層型DBMSでは、二次索引を使って特定のセグメントを見つけた後、ルートまで遡る(あるいは子を辿る)際に、物理ポインタが切れていたり、再編成(Reorg)のタイミングが悪かったりすると、アクセス速度は劇的に低下する。
チューニングのポイント
1. インデックスのセパレート: インデックス領域をメインのデータ領域と異なる物理ディスク(あるいは異なる論理ボリューム)に配置せよ。I/O競合を物理的に排除する。
2. ポインタの最適化: 索引定義において「直接アドレス」か「物理的な相対位置」かを選択できる場合、更新頻度と再編成コストを天秤にかけろ。頻繁に再編成するDBでは相対位置指定の方が安全だ。
—
4. チーフアーキテクトからの提言
「二次索引があれば、リレーショナルDBのようにクエリを投げられる」という幻想は捨てろ。階層型DBは、物理構造(セグメントの並び)が設計のすべてだ。
もしあなたが「検索項目が多すぎて、二次索引を何個も作らなければならない」という状況に陥っているなら、それはDBの設計ミスだ。その場合は、「検索結果を格納する専用のサマリセグメント」を物理的に最上層に置くなど、階層構造そのものを見直せ。
コードやクエリでカバーしようとするな。物理的なデータ配置で勝負しろ。
二次索引は、あくまで「最後の手段」だ。設計の美しさは、無駄な索引を削ぎ落とした先に見えてくる。今日のレビューはここまでだ。各自、自身の設計したスキーマが「ポインタの迷宮」になっていないか、今一度見直しておくように。
コメント