JSONとJSONBの主な違いの一つは、データの保存フォーマットだよ。JSONはデータをテキストとして保存するけど、JSONBはバイナリ形式で保存する。つまり:
- JSONは、渡したデータをそのまま保存する。たとえば、
{"title": "PostgreSQL", "tags": ["database", "SQL"]}という文字列を挿入したら、そのまま保存される。 - JSONBは、まずJSONオブジェクトをパースして、余計なスペースを消して、キーを並べ替えて、構造を最適化してからバイナリ形式で保存する。
この最適化のおかげで、JSONBは特に複雑なフィルタや検索、ソートのクエリでデータ処理が速くなるんだ。
読み書きパフォーマンス
JSONとJSONBは、データの読み書き速度に違いがある:
- JSONは、保存前にパースしなくていいから書き込みが速い。でも、読み込みや処理は遅くなりがち。なぜなら、PostgreSQLがクエリ実行時に毎回パースし直す必要があるから。
- JSONBは、保存前にデータを処理するので書き込みは遅め。でも、読み込みやフィルタ、値の抽出はかなり速い。だから分析や検索系の用途にはJSONBがオススメ。
イメージしやすい例:
-- JSONとJSONBのテーブル作成
CREATE TABLE json_example (data JSON);
CREATE TABLE jsonb_example (data JSONB);
-- データ挿入
INSERT INTO json_example VALUES ('{"key": "value", "tags": ["json", "example"]}');
INSERT INTO jsonb_example VALUES ('{"key": "value", "tags": ["jsonb", "example"]}');
-- データのフィルタ
SELECT * FROM json_example WHERE data->'key' = '"value"'; -- 遅い
SELECT * FROM jsonb_example WHERE data->'key' = '"value"'; -- 速い
データのインデックス化
JSONBの最大のメリットの一つはインデックス対応。PostgreSQLはJSONBカラムにGINインデックスを作れる。これで検索やフィルタがめっちゃ速くなる!
インデックス作成例:
-- JSONBカラムのインデックス
CREATE INDEX idx_jsonb_tags ON jsonb_example USING gin (data->'tags');
逆にJSONはインデックス非対応なので、複雑な検索やフィルタには向いてない。
JSONとJSONB、どっちを使う?
JSONが向いてるケース:
- データをそのままの形で保存したい時。
- JSONデータでフィルタや検索、ソートをあまりしない場合。
- JSONデータを他のシステムやクライアントにそのまま渡す用途(例:API経由でフロントエンドに返すなど)。
例:
-- 解析せずにJSONを保存
CREATE TABLE api_responses (
id SERIAL PRIMARY KEY,
response JSON
);
-- APIから来たデータをそのまま挿入
INSERT INTO api_responses (response)
VALUES ('{"status": "success", "payload": {"id": 123, "name": "John"}}');
JSONBがオススメな場合:
- JSON内の値でフィルタ、検索、グループ化、ソートをよく使う時。
- データアクセスのパフォーマンスが書き込み速度より大事な時。
- JSONデータの操作を速くするためにインデックスを使いたい時。
例:
-- 分析やネストしたオブジェクト操作用にJSONBを保存
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSONB
);
-- データ挿入
INSERT INTO products (details)
VALUES ('{"name": "Laptop", "price": 1200, "tags": ["electronics", "computers"]}');
-- "electronics"タグ付き商品を検索
SELECT * FROM products
WHERE details @> '{"tags": ["electronics"]}';
@>や-->演算子については次のレクチャーで詳しくやるよ :P
JSONとJSONBの操作例
JSONカラムとJSONBカラムの2つのテーブルを作ってみよう:
CREATE TABLE json_table (
id SERIAL PRIMARY KEY,
data JSON
);
CREATE TABLE jsonb_table (
id SERIAL PRIMARY KEY,
data JSONB
);
どちらのテーブルもデータの挿入方法は同じ:
INSERT INTO json_table (data)
VALUES ('{"key": "value", "tags": ["json", "example"]}');
INSERT INTO jsonb_table (data)
VALUES ('{"key": "value", "tags": ["jsonb", "example"]}');
次に、keyがvalueのデータを抽出してみる:
-- JSONの場合
SELECT * FROM json_table
WHERE data->>'key' = 'value';
-- JSONBの場合
SELECT * FROM jsonb_table
WHERE data->>'key' = 'value';
データ量が少ないうちはパフォーマンス差はほぼない。でも、何百万行も扱う場合はJSONBが圧倒的に速くなる。特にインデックスを作れば:
CREATE INDEX idx_jsonb_key ON jsonb_table USING gin ((data->>'key'));
ネストしたオブジェクトや配列の操作もJSONBの方が効率的:
-- 配列から値を取り出す
SELECT data->'tags'->>0 AS first_tag
FROM jsonb_table;
メリット・デメリットまとめ
| 特徴 | JSON | JSONB |
|---|---|---|
| データ保存 | 元のテキスト形式で保存 | キーを並べ替えてバイナリ形式で保存 |
| 書き込みパフォーマンス | そのまま保存なので速い | 事前パースがあるので遅め |
| 読み込みパフォーマンス | クエリ時にパースが必要なので遅い | 最適化済みなので速い |
| インデックス | 非対応 | 対応(GIN、BTREEインデックス) |
| フィルタ | 遅い | 速い |
| 操作サポート | 限定的 | 拡張されている |
JSONとJSONBの選択は用途次第。単にテキストのままデータを保存したいだけならJSONでOK。でも、カラム内のデータをガンガン操作したり、フィルタや検索、グループ化をしたいなら、JSONBの方がパフォーマンスも使い勝手も良いよ。
複雑なアプリで、JSONデータが「ただの保存場所」じゃなくて分析にも使うなら、JSONBはマジで必須。迷ったらとりあえずJSONBにしとこう。きっと将来「人生最速クエリ」が出せて感謝されるはず!
GO TO FULL VERSION