【実務・中級編】 JSONB型 – PostgreSQL

「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」というスタンスで設計してみてほしい。

そうすれば、君の書くデータベース設計は、将来の拡張性に耐えられる、美しく力強いものになるはずだよ。

何か具体的な設計で悩んだら、いつでもコードを持ってきてくれ。一緒に最適解を探そう。

コメント

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