「JSONBは魔法の杖じゃない」——PostgreSQLでJSONBと上手く付き合うための現実的な設計論
「とりあえずJSONB型に入れておけば後でなんとかなるでしょ」。
もし君がそう思って、テーブルの設計をサボろうとしているなら……ちょっと待って。今日は、PostgreSQLの強力な武器である「JSONB」について、現場の知見を交えてじっくり語らせてくれ。
JSONBは確かに便利だ。でも、使い方を間違えると、システムが成長した時に「重すぎてクエリが返ってこない」という悲劇を招くことになる。この記事では、JSONBの仕組みから、実務で刺さるインデックス設計まで、綺麗事抜きで解説していくよ。
—
1. なぜ「JSONB」なのか?(JSON型との決定的な違い)
PostgreSQLには`JSON`型と`JSONB`型があるよね。これ、初心者は混乱しがちだけど、実務では迷わずJSONB一択だ。
- JSON型: テキストとして保存される。パースのコストが毎回発生する。
- JSONB型: 「Binary」の略。パース済みのバイナリ形式で保存される。
JSONBは保存時に少しコストがかかるけど、読み出し時のパフォーマンスが圧倒的に速い。それに、インデックスを貼れるのもJSONBの特権だ。テキストのまま保存するJSON型を使う理由は、正直「保存した時と全く同じ空白文字を維持したい」という稀なケースくらいだよ。
—
2. JSONBの「賢い」操作術
JSONBを扱う時、無理に複雑なSQLを書こうとしていないかな?まずは基本の演算子をおさらいしよう。
よく使う演算子
- `@>`(包含演算子): 「これを含んでいるか?」をチェックする。インデックスが効くので、検索の要だ。
- `->` と `->>`: フィールドへのアクセス。`->`はJSONBオブジェクトを返し、`->>`はテキスト(文字列)を返す。ここ、間違えると比較演算でハマるから注意してね。
実践的なコード例
例えば、ユーザーの属性情報をJSONBで持っている場合:
— “tags”というキーの中に”active”という値が含まれているか検索
SELECT FROM users
WHERE properties @> ‘{“tags”: [“active”]}’;
— 属性から特定の値を抽出して集計
SELECT properties->>’region’ AS region, count()
FROM users
GROUP BY 1;
ここでポイントなのが、`->>`は必ずテキストとして返すということ。もし数値として扱いたいなら、キャストを忘れないように。「`(properties->>’age’)::int > 20`」といった具合だね。
—
3. インデックス設計:ここが勝負所
JSONBの真骨頂は「GINインデックス」にある。これがないと、全件スキャン(Seq Scan)が走ってテーブルが大きくなるほど瀕死になる。
GINインデックスの基本
CREATE INDEX idx_users_properties ON users USING GIN (properties);
これで`@>`演算子を使った検索が劇的に速くなる。でも、これだけで満足してはいけない。
現場のTips:インデックスの「絞り込み」
もし検索条件が特定のキーに集中しているなら、`jsonb_path_ops`を使うのが賢いやり方だ。
CREATE INDEX idx_users_properties_path ON users USING GIN (properties jsonb_path_ops);
デフォルトのGINよりインデックスサイズが小さくなり、検索速度も向上することが多い。ただし、特定の演算子(`@>`など)しか使えなくなるトレードオフがある。この辺りは要件と相談だね。
—
4. 先輩からの最後のアドバイス:逃げ道としてのJSONB
ここが一番伝えたいことなんだけど、「リレーショナルにできることは、リレーショナルに設計する」のが鉄則だ。
JSONBは、スキーマが頻繁に変わるメタデータや、疎なデータ(人によって持っている項目がバラバラなデータ)には最適だ。でも、検索条件に必須となるIDや状態フラグまでJSONBに突っ込むのはアンチパターンだよ。
- JSONBを使うべき時:
- データ構造が柔軟すぎて、テーブル設計を固定すると`NULL`だらけになる時。
- 外部APIから取得したレスポンスをそのまま保存したい時。
- JSONBを避けるべき時:
- 結合(JOIN)のキーにする時。
- 厳密な型制約(NOT NULLやCHECK制約)が必要な時。
まとめ
JSONBは、PostgreSQLというリレーショナルデータベースが持つ「堅牢さ」と、NoSQLのような「柔軟さ」を繋ぐブリッジだ。この二つの特性を理解して、「メインはリレーショナル、柔軟性が必要な場所だけJSONB」というスタンスで設計してみてほしい。
そうすれば、君の書くデータベース設計は、将来の拡張性に耐えられる、美しく力強いものになるはずだよ。
何か具体的な設計で悩んだら、いつでもコードを持ってきてくれ。一緒に最適解を探そう。
コメント