Zenn
🐙

json型のデメリット

2025/03/15に公開

Daily Blogging84日目

RDBのjson型はスキーマレスに使えて色々便利に見えるけど、ちゃんとデメリットもあるので注意が必要

json型のデメリット

ざっくりこんな感じのデメリットがある

  • 古いバージョンのORMはそもそもサポートしてないケースが多い
  • 検索時のクエリが複雑になる
  • 整合性が取れない
  • 型指定ができない

古いバージョンのORMはそもそもサポートしてないケースが多い

最新のバージョンであればjson型やjsonb型をサポートしているORMも多いが、
バージョンが古いとサポートされていないことが多い
サポートされていない場合、jsonデータを登録/更新/検索する操作がさらに難しくなる

検索時のクエリが複雑になる

ORMがjson型をサポートしていたとしても、クエリが通常よりも複雑になりがち
↓ActiveRecordの場合

# cityというキーに紐づく値がTokyoのレコードを取得するクエリ
User.where("profile->>'city' = ?", "Tokyo")

jsonデータがネストしている場合、もっと見づらい

User.where("profile->'address'->>'zipcode' = ?", "12345")

曖昧検索したいなら

User.where("profile->'skills' @> ?", '["Ruby"]')

検索条件が複雑になるともっとクエリも複雑になるよ

json型の場合、インデックスも適用されない
※jsonb型ならGinインデックスが使える

整合性が取れない

外部キー制約もユニーク制約も適応できないので、不正な値が入る可能性が高い。

CHECK制約で、特定の属性を必須にすることは可能
でも制約の変更が面倒臭い

jsonb型の場合

jsonb_exists関数が使える

ALTER TABLE users ADD CONSTRAINT check_profile_has_age
CHECK (jsonb_exists(profile, 'age'));

json型の場合

やや面倒くさい

ALTER TABLE users ADD CONSTRAINT check_profile_has_age
CHECK ((profile->'age') IS NOT NULL);

必須属性を増やす場合

-- 一回制約をドロップして
ALTER TABLE users DROP CONSTRAINT check_profile_age;

-- 新しく作り直す必要がある
ALTER TABLE users ADD CONSTRAINT check_profile_age_and_address
CHECK (
  profile->'age' IS NOT NULL AND
  json_typeof(profile->'age') = 'number' AND
  profile->'address' IS NOT NULL
);

型指定ができない

値の型を指定できないので、同じ意味合いの値でもフォーマットが異なる可能性がある。
日付の場合
yyyy-mm-dd
yyyy/mm/dd
とか表記触れが発生することも

json型の使い所

上記のデメリットが適用されない時になら使ってもそんな支障ない

Discussion

ログインするとコメントできます