MLOpsのDBには「推論リクエストログ」「学習データ」「モデルメタ情報」など、柔軟に変化するデータが多く入ってきます。そこでよく使われるのが JSONB。
JSONBとは?
PostgreSQLが提供する JSON型の拡張版 です。
通常のJSONは「文字列」として保存されますが、JSONBは バイナリ形式 で保存され、次のような特徴があります:
- JSON構造を解析済みで保存するため、検索や比較が高速
- キーや値を個別に抽出しやすい
- インデックス(特にGINインデックス)を使うと検索性能が向上
つまり、「JSONの柔軟性」と「DBらしい検索性能」の両方をある程度兼ね備えたデータ型です。
JSONBのメリット
- スキーマ変更なしで新しいフィールドを追加できる
- メタ情報や可変パラメータの保存に便利
- GINインデックスを張れば検索もそこそこ速い
JSONBに頼りすぎると…
- クエリが複雑化して読みづらい
- 正規化されていないためJOINが難しい
- 一部だけを集計するときにパフォーマンスが落ちる
JSONBの使いどころ
- 可変的なデータ構造の保存
例: 推論結果の詳細、リクエスト時の可変パラメータ - スキーマが頻繁に変わる情報
例: モデルのメタ情報(ハイパーパラメータ、環境設定など) - ログやイベントの詳細
共通の枠組みは正規化しておき、詳細はJSONBに入れることで柔軟性を確保 - 検索頻度が低いが保持しておきたいデータ
例: デバッグ用の詳細情報や、まれに使う属性
うまい使い分けの指針
- 基本の軸は正規化テーブル
- 例:
inference_logs(id, created_at, user_id, model_id, result_jsonb)
- 例:
- 変化しやすい部分をJSONBに閉じ込める
- resultの詳細やリクエストパラメータなど
- 検索頻度の高いキーは正規化してカラム化する
- 例:
status
やlatency_ms
は専用カラムを持たせる
- 例:
クエリ例(JSONBとカラムの併用)
-- 正規化したカラムでの高速検索
SELECT id, created_at, status
FROM inference_logs
WHERE status = 'success'
AND created_at >= now() - interval '1 day';
-- JSONB内の柔軟検索
SELECT id, result->>'score' AS score
FROM inference_logs
WHERE (result->>'model_version')::int = 3;
✅ 今日のまとめ
Aurora/PostgreSQLでは 「安定した軸は正規化、変化の激しい部分はJSONB」 が鉄則。
柔軟性とパフォーマンスのバランスを取ることが、長期運用に効いてきます。