CodeGym /コース /SQL SELF /JSONデータ操作でよくあるミスとその防止方法

JSONデータ操作でよくあるミスとその防止方法

SQL SELF
レベル 34, レッスン 4
使用可能

PostgreSQLでJSONデータを扱うのはめっちゃ強力だけど、どんなツールも使い方には注意が必要。ちょっとしたミスでクエリが謎解きみたいになっちゃうこともある。
今日はまた、PostgreSQLでJSONやJSONBを使うときによくあるミスと、その防ぎ方にフォーカスしていくよ。

問題1: JSONをJSONBの代わりに使っちゃう

初心者がよくやるのが、JSON型を選んじゃうこと。「JSONデータならこれでしょ!」って思いがちだけど、PostgreSQLのJSONはテキスト形式で保存されるから、検索やフィルタが遅くなりやすいんだ。

ミスの例:

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    details JSON
);

INSERT INTO products (details) VALUES ('{"name": "ノートパソコン", "price": 1000}');

INSERT INTO products (details) VALUES ('{"name": "ノートパソコン", "price": 1000}');

例えばpriceキーでフィルタしようとすると、JSONBに比べてかなり遅くなるよ。

どう直すか:
データをよくフィルタしたりアクセスするなら、JSONBを使おう。

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    details JSONB
);

問題2: JSONBにインデックスを貼ってない

JSONBは超強力だけど、インデックスがないと複雑なクエリでパフォーマンスがガタ落ちする。

ミスの例:たとえばdetailsカラムに大量のJSONオブジェクトを保存してるテーブルがあるとする:

SELECT * FROM products WHERE details->>'name' = 'ノートパソコン';

インデックスがなければ、サーバーは全件スキャン(full table scan)しちゃって、めっちゃ時間かかる。

どう直すか:
キー検索を速くするためにGINインデックスを作ろう:

CREATE INDEX idx_details_name ON products USING gin (details jsonb_path_ops);

問題3: ネストしたデータの取り出しミス

ネストしたオブジェクトや配列からデータを抜き出すとき、->と->>の違いを知らないと混乱しがち。

ミスの例:

SELECT details->'price' FROM products;

このクエリはJSON形式の値を返す("1000"じゃなくて1000が欲しい場合)。値だけ欲しいなら->>を使おう:

SELECT details->>'price' FROM products;

問題4: 演算子の使い方ミス

@>演算子を見て「これ便利そう!」って思って何でも使っちゃうと、思わぬ結果になることがある。

ミスの例:

SELECT * FROM products WHERE details @> '{"price": 1000}';

このクエリは、priceがJSON内で数値の場合だけヒットする。もし値が文字列"1000"なら、何も返ってこない。

どう直すか:
JSON内のデータ型に注意しよう:

SELECT * FROM products WHERE details->>'price' = '1000';

問題5: デカいJSONオブジェクト

最適化せずに大きなJSONオブジェクトを保存すると、クエリがめっちゃ遅くなる。しかも、JSONBの一部だけ変えたい場合でも、全体を処理し直す必要がある。

どう直すか:
よく使うキーは別カラムに分けよう。例えば:

ALTER TABLE products ADD COLUMN price NUMERIC;
UPDATE products SET price = (details->>'price')::NUMERIC;

これでJSONBを解析しなくても、効率よくフィルタやソートができる。

問題6: オブジェクト全体の再構築が発生する

jsonb_set()やjsonb_insert()みたいな関数を使うと、PostgreSQLは新しいJSONBオブジェクトを丸ごと作り直す。これがパフォーマンス的に重い。

どう直すか:
JSONBの更新回数を減らそう。例えば、何回も小分けで更新するより、一度にまとめて更新するのがベター:

UPDATE products
SET details = jsonb_set(details, '{price}', '1500'::jsonb);

問題7: 配列構造の理解不足

JSONBの配列も注意が必要。例えば、こんな配列があるとする:

{
    "tags": ["電子機器", "ノートパソコン", "セール"]
}

"ノートパソコン"タグがあるか調べたいとき、@>演算子を間違って使うと、結果が返ってこないことがある。なぜなら、演算子は配列を期待してるから。

ミスの例:

SELECT * FROM products WHERE details->'tags' @> '"ノートパソコン"';

どう直すか:
@>演算子には正しいフォーマットを使おう:

SELECT * FROM products WHERE details->'tags' @> '["ノートパソコン"]';

ミス防止のためのアドバイス

JSONBを使うときにトラブルを避けるには、次のポイントを意識しよう:

正しいデータ型を選ぶ。 データ量が多くてフィルタもよく使うなら、必ずJSONBを選ぼう。

インデックスを貼る。 よく使うキーがあるなら、適切なインデックス(例:GIN)を作ろう。

挿入前にデータをチェック。 データ構造をバリデーションする関数を使おう:

DO $$
BEGIN
    IF jsonb_typeof('{"price": 1000}'::jsonb->'price') IS DISTINCT FROM 'number' THEN
        RAISE EXCEPTION '価格は数値でなきゃダメだよ';
    END IF;
END $$;

データ構造を最適化する。 よく使うキーは別カラムに抜き出そう。

演算子や関数をちゃんと調べる。 PostgreSQL公式ドキュメントをよく読んで、->、->>、@>、?|などの違いを理解しよう。

JSONやJSONBは、柔軟で複雑なデータを扱うときの強い味方。大事なのは、ツールの選び方に気をつけて、よくあるミスを避けること。そうすれば、コードも効率的でメンテしやすくなるよ!

2
タスク
SQL SELF, レベル 34, レッスン 4
ロック未解除
JSONBの値によるデータのフィルタリング
JSONBの値によるデータのフィルタリング
1
アンケート/クイズ
JSONオブジェクトのデータ更新、レベル 34、レッスン 4
使用不可
JSONオブジェクトのデータ更新
JSONオブジェクトのデータ更新
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION