はじめに
この記事では、IBM Db2のBuffer Poolの内部構造を解説します。
InnoDB編、PostgreSQL編、Oracle編、SQL Server編に続く第5弾・最終回です。5つの主要RDBMSのBuffer管理を比較するシリーズの締めくくりとして、Db2ならではの特徴を中心に解説します。
Db2はLUW(Linux/UNIX/Windows)版とz/OS版で実装が異なりますが、この記事ではLUW版を中心に、z/OS版の特徴にも触れます。
Db2 Buffer Poolの基本
Db2のBuffer Poolは他のDBMSと同じく、ディスク上のデータページをメモリにキャッシュする仕組みです。
-- デフォルトBuffer Pool
-- データベース作成時に IBMDEFAULTBP が自動作成される
-- Buffer Poolの作成
CREATE BUFFERPOOL my_bp
SIZE 50000 -- ページ数
PAGESIZE 8K; -- 4K, 8K, 16K, 32K から選択
-- Buffer Poolの変更(オンラインで即時反映)
ALTER BUFFERPOOL my_bp SIZE 100000;
-- Buffer Poolの情報確認
SELECT * FROM SYSCAT.BUFFERPOOLS;Db2固有の特徴:ページサイズとBuffer Poolの紐づけ
Db2ではテーブルスペースとBuffer Poolのページサイズが一致している必要があります。4K、8K、16K、32Kの4種類があり、ページサイズごとにBuffer Poolを用意します:
| 名前 | ページサイズ | 用途 |
|---|---|---|
| IBMDEFAULTBP | 4K | デフォルト |
| IBMSYSTEMBP4K | 4K | システム用 |
| IBMSYSTEMBP8K | 8K | システム用 |
| IBMSYSTEMBP16K | 16K | システム用 |
| IBMSYSTEMBP32K | 32K | システム用 |
| MY_BP_8K | 8K | ユーザー定義 |
| MY_BP_32K | 32K | ユーザー定義 |
テーブルスペース(8K) → MY_BP_8K にのみ割り当て可能 テーブルスペース(32K)→ MY_BP_32K にのみ割り当て可能
これはOracleのKeep/Recycle Poolに似ていますが、Db2の方がより柔軟です。ワークロードの特性に応じて、テーブルごとに最適なBuffer Poolを割り当てられます。
Page Stealing アルゴリズム:3つの選択肢
Db2の最大の特徴は、ページ置換アルゴリズムを選択できることです。他のDBMSでは置換アルゴリズムは固定ですが、Db2(特にz/OS版)では3つから選べます:
PGSTEAL(LRU):デフォルト
ALTER BUFFERPOOL my_bp PGSTEAL LRU;最も一般的な選択肢です。最近使われていないページから優先的に追い出します。InnoDBのLRU Listに近い動作です。
ただし、LRUチェインの維持コストとラッチ競合が発生します。
PGSTEAL(FIFO):先入れ先出し
ALTER BUFFERPOOL my_bp PGSTEAL FIFO;最も古くBuffer Poolに入ったページから追い出します。アクセス頻度は考慮しません。
LRUチェインの維持が不要なため、ラッチ競合が少なくなります。Buffer Poolが十分に大きく、ほぼすべてのデータがメモリに載る場合に有効です。
PGSTEAL(NONE):追い出しなし
ALTER BUFFERPOOL my_bp PGSTEAL NONE;オブジェクトがオープンされると全ページをBuffer Poolにプリロードし、可能な限りメモリに常駐させます。サイズが安定していて頻繁にアクセスされるテーブル向けです。
OracleのKeep Poolに近い概念ですが、Db2の方がより積極的(プリロードまでする)です。
5つのDBMSの置換アルゴリズム比較
| DBMS | アルゴリズム | 選択可能? | スキャン耐性 |
|---|---|---|---|
| InnoDB | LRU(New/Old Sublist) | ❌ | Old Sublist分割 |
| PostgreSQL | Clock Sweep | ❌ | Ring Buffer |
| Oracle | LRU + Touch Count | ❌ | Direct Path Read |
| SQL Server | Clock(参照ビット) | ❌ | 参照ビットリセット |
| Db2 | LRU / FIFO / NONE | ✅ | アルゴリズム選択 + Prefetch |
Prefetch(先読み)とPage Cleaner
Prefetch:I/Oの先読み
Db2のPrefetchは、InnoDBのRead-Aheadに相当します。テーブルスキャンやインデックススキャン時に、次に必要になるページを先回りして読み込みます:
-- Prefetch関連の設定
-- テーブルスペースレベルで設定
CREATE TABLESPACE my_ts
PAGESIZE 8K
PREFETCHSIZE 32 -- 一度に先読みするページ数
BUFFERPOOL my_bp;
-- Prefetchの統計確認
SELECT
bp_name,
pool_data_p_reads, -- 物理読み取り
pool_async_data_reads, -- 非同期(Prefetch)読み取り
pool_data_l_reads -- 論理読み取り(Buffer Poolヒット)
FROM SYSIBMADM.BP_READ_IO;pool_async_data_reads / pool_data_p_readsの比率が高いほど、Prefetchが効果的に機能しています。
Page Cleaner:ダーティページの書き出し
Db2のPage Cleanerは、InnoDBのpage cleaner、PostgreSQLのBGWriter、OracleのDBWnに相当します:
-- Page Cleanerの数を設定
-- データベース構成パラメータ
db2 UPDATE DB CFG FOR mydb USING NUM_IOCLEANERS 4;Page Cleanerは以下のタイミングで起動します:
- ダーティページ率が閾値(chngpgs_thresh)を超えた
- デフォルト60%
- LSN Gap が大きくなりすぎた
- ログの再利用のためにチェックポイントを進める必要
- InnoDBのアクティブRedo量による圧力と同じ概念
- Freeページが不足した
-- Page Cleanerの活動を監視
SELECT
bp_name,
pool_async_data_writes, -- Page Cleanerによる非同期書き出し
pool_data_writes, -- 全書き出し
pool_drty_pg_steal_clns -- ダーティページの追い出し(同期書き出し)
FROM SYSIBMADM.BP_WRITE_IO;pool_drty_pg_steal_clnsが高い場合、Page Cleanerが間に合っていないサインです。NUM_IOCLEANERSの増加やchngpgs_threshの引き下げを検討します。
Buffer Poolの監視
スナップショットによる監視
-- Buffer Poolのヒット率
SELECT
bp_name,
pool_data_l_reads AS logical_reads,
pool_data_p_reads AS physical_reads,
CASE WHEN pool_data_l_reads > 0
THEN DECIMAL((1.0 - FLOAT(pool_data_p_reads) / pool_data_l_reads) * 100, 5, 2)
ELSE 0
END AS hit_ratio_pct
FROM SYSIBMADM.SNAPBP;MON_GET_BUFFERPOOL テーブル関数
-- より詳細なBuffer Pool統計(Db2 10.5+)
SELECT
bp_name,
pool_data_lbp_pages_found, -- ローカルBuffer Poolでのヒット
pool_data_gbp_p_reads, -- グループBuffer Poolからの読み取り(pureScale)
pool_async_data_reads,
pool_async_data_writes
FROM TABLE(MON_GET_BUFFERPOOL(NULL, -2)) AS t;まとめ:5つのDBMSの総比較
シリーズ全体の締めくくりとして、5つのDBMSのBuffer管理を一覧で比較します。
| テーマ | InnoDB | PostgreSQL | Oracle | SQL Server | Db2 |
|---|---|---|---|---|---|
| 置換アルゴリズム | LRU(New/Old) | Clock Sweep | LRU + Touch Count | Clock | LRU/FIFO/NONE選択可 |
| スキャン耐性 | Old Sublist | Ring Buffer | Direct Path Read | 参照ビット | アルゴリズム選択 |
| ダーティ管理 | Flush List | なし | Checkpoint Queue | なし(走査) | LSN Gap監視 |
| 書き出しプロセス | page cleaner | BGWriter + Checkpointer | DBWn + CKPT | Lazy Writer + Checkpoint | Page Cleaner |
| プール分割 | インスタンス分割 | 単一 | Default/Keep/Recycle | 単一 | ページサイズ別 |
| ソースコード | ✅ 公開 | ✅ 公開 | ❌ 非公開 | ❌ 非公開 | ❌ 非公開 |
| 可観測性 | SHOW STATUS | pg_buffercache | XBH, VLATCH | DMV | スナップショット, MON_GET |
5つのDBMSを通して見えてくるのは、Buffer管理という同じ問題に対して、各DBMSが独自の解を持っていることです。しかし根底にある設計目標は共通しています:ディスクI/Oを最小化し、同時実行性能を維持すること。
このシリーズが、データベースの内部構造を理解する一助になれば幸いです。