📝

複数列属性のDB設計について考えてみた

2024/09/23に公開

転職のためのユーザーと企業をマッチングするサービス。
当初はスキルを1個しか登録できない予定だったが、仕様変更により3個まで登録できるようになったため、とりあえずスキルidカラムを3個に増やして対応した。

テーブル構造

変更対応後、「動作が遅くなった」「2個しか登録できない」といった問い合わせが増えたため、
設計を見直すことにした。

問題点

この設計には以下のような問題が発生してしまうことがわかった。

検索が非効率

特定の値が存在するUsersを検索する場合、3列すべて取得しないといけない。

SELECT * FROM Users
WHERE skill1id = 'スキルA'
OR skill2id = 'スキルA'
OR skill3id = 'スキルA';

データが重複してしまう可能性がある

ユニーク制約を設定することが難しいため、skill1id, skill2id, skill3idに重複したデータが入ってしまう可能性がある。

タグの登録数を増やす場合に問題が発生する可能性がある

  • テーブルに関係するすべてのクエリの見直しが必要になる
  • テーブル全体をロックしないといけなくなってしまう可能性がある

どのように解決するか

UsersからSkillsの多対多関係を中間テーブルUserSkillsで管理することで、以下のような改善が可能だと考えられる。

クエリの効率化

JOINを使ったクエリによって、効率的にスキルを持つユーザーを取得できるようになる。
スキルごとのユーザー検索において冗長なOR条件が不要となるため、効率的な検索が可能になる。

SELECT u.*
FROM Users u
JOIN UserSkills us ON u.user_id = us.user_id
WHERE us.skill_id = 'スキルA';

データ重複問題の解決

中間テーブルであるUserSkillsに対して、user_idskill_idの組み合わせにユニーク制約を付けることで、同じユーザーに同じスキルが複数回登録されるのを防ぐことができる。

スキルの拡張性

テーブルを変更することなく登録数を増やすことができるため、サービスを停止せずに運用が可能になる。

参考文献

https://www.oreilly.co.jp/books/9784873115894/

Discussion