CodeGym /コース /SQL SELF /JSONBデータのインデックス作成: GINと BTREEインデックスの使い方

JSONBデータのインデックス作成: GINと BTREEインデックスの使い方

SQL SELF
レベル 38, レッスン 0
使用可能

最初の疑問:「なんでそもそもJSONB使うの?」って話。JSONBはJSONフォーマットでデータを保存できて、構造が柔軟なんだ。たとえば、ユーザープロフィールにアドレスや設定のリストがあるみたいな、複雑でネストしたデータにめっちゃ便利。普通のJSONと違って、JSONBはバイナリ形式で保存されるから、検索やフィルタリングがかなり速くなる。

でも、インデックスなしだとJSONBの検索は結構遅い。特にテーブルに何千、何百万行もあるときはヤバい。例えば、ユーザー情報のテーブルがあって、各ユーザーの設定をJSONBで保存してるとする。インデックスなしで特定の設定値を持つユーザーを探すのは、めっちゃリソース食う作業。そこでインデックスの出番ってわけ!

JSONBのインデックス作成:大事なポイント

PostgreSQLでJSONBをインデックス化するには、主に2つの方法があるよ:

  1. GIN (Generalized Inverted Index) — JSONBの中のキーや値で検索する用。
  2. BTREE — シンプルな検索やソート用。

それぞれ特徴があるから、詳しく見ていこう。

JSONB用のGINインデックス

GINは強力なインデックスで、配列やテキスト、JSONBデータにも使える。JSONBオブジェクトの中身をキーと値に分解して、素早く検索できる特別な構造を作ってくれるんだ。

JSONBにGINを使うメリット:

  • キーでも値でも検索できる。
  • ネストした構造にも対応。
  • @>、?、?|、?&みたいな演算子(キーや値のフィルタリング)が速くなる。

例えば、usersテーブルがあって、settingsカラムにユーザー設定をJSONBで保存してるとする。データ例はこんな感じ:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name TEXT,
    settings JSONB
);

INSERT INTO users (name, settings) VALUES
('Alice', '{"theme": "ダーク", "notifications": {"email": true, "sms": false}}'),
('Bob', '{"theme": "ライト", "notifications": {"email": false, "sms": true}}'),
('Charlie', '{"theme": "ダーク", "notifications": {"email": true, "sms": true}}');

今度は「ダーク」テーマのユーザーをサクッと探したい。まずはインデックスを作成:

CREATE INDEX idx_users_settings_gin ON users USING GIN (settings);

次に@>演算子で検索:

SELECT name
FROM users
WHERE settings @> '{"theme": "ダーク"}';

これでPostgreSQLはGINインデックスを使って、検索がめっちゃ速くなる。

どうやって動いてるの?JSONBカラムにGINインデックスを作ると、PostgreSQLは「逆引き」インデックスを作る。つまり、JSONの全キーと値ごとに個別のエントリを作るんだ。例えば:

{"theme": "ダーク", "notifications": {"email": true, "sms": false}}

このオブジェクトからtheme、notifications.email、notifications.smsとその値でインデックス化される。だから個々の要素の検索が爆速になる。

JSONB用のBTREEインデックス

BTREEはクラシックなインデックス。JSONBオブジェクト全体を比較したり、ソートしたいときに使う。でもGINと違って、JSONオブジェクトの中身までは分解しない。

JSONBにBTREEを使うメリット:

  • オブジェクトの比較やソートに最適。
  • JSONBを「かたまり」として使う場合(他のオブジェクトと比較したり、特定の値と一致する行を探すとき)は速い。

使い方の例を見てみよう。 例えばusersテーブルで、settingsカラムを特定のオブジェクトとよく比較する場合:

{"theme": "ダーク", "notifications": {"email": true, "sms": false}}

まずはインデックスを作成:

CREATE INDEX idx_users_settings_btree ON users USING BTREE (settings);

これでオブジェクト比較のクエリができる:

SELECT name
FROM users
WHERE settings = '{"theme": "ダーク", "notifications": {"email": true, "sms": false}}';

このクエリはBTREEインデックスを使って速くなるよ。

GINとBTREEの比較

特徴 GIN BTREE
JSONBオブジェクトの分解 はい、キーと値に分解する いいえ、全体で比較
ネスト構造の検索 はい いいえ
ソート いいえ はい
インデックスサイズ 大きい 小さい
対応演算子 @>, ?, ?|, ?& =, <, >など

つまり、GINは複雑なクエリ向き、BTREEはオブジェクト全体の比較やソート向きってこと。

どっちのインデックスを選ぶ?

  • JSONBの中のキーや値で検索したいならGINを使おう。
  • JSONBオブジェクト全体を比較したりソートしたいならBTREEがいいよ。

でも、両方のインデックスを同じカラムに作るのも全然アリ!テーブルで両方のクエリが必要なら、GINとBTREE両方作っちゃおう。

JSONBインデックスでありがちなミス

不要なインデックスの作成:全部のJSONBフィールドにインデックスを貼るのはやめとこう。インデックスは容量を食うし、INSERTやUPDATEも遅くなる。

あまり使わない演算子のインデックス化:「なんとなく正しそう」って理由だけでインデックスを作るのはNG。クエリをちゃんと分析して、本当に速くなるところだけインデックスを使おう。

GINの特徴を無視する:GINはBTREEよりインデックス作成に時間がかかることもある。大きなテーブルでは特に注意しよう。

実践での使いどころ

JSONBは、データが柔軟で動的なリアルなプロジェクトで役立つよ。例えば:

  • ユーザー設定があるWebアプリ。
  • イベントごとに違うフィールドを持つログの保存。
  • JSON形式でのデータキャッシュ。

こういうデータをGINやBTREEでインデックス化すると、クエリのパフォーマンスがめっちゃ上がる。面接とかでも、「複雑なデータ構造にインデックスを追加してシステムを速くした」って話せるとカッコいいよ。

PostgreSQLの公式JSONインデックスドキュメントはここで見れる。困ったらチェックしてみて!

2
タスク
SQL SELF, レベル 38, レッスン 0
ロック未解除
JSONB検索用のGINインデックスを作成しよう
JSONB検索用のGINインデックスを作成しよう
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION