ほんまに一対多でええんか?
こんにちは。株式会社プラハCEOの松原です。
今日は「ほんまに一対多でええんか?最初から多対多テーブルにしておいて備える方法もあるよ」というDB設計周りの話について書いてみます
一対多が多対多になる時に備える
こういうユースケースに直面した時・・・
ユーザーは記事を複数作成できる
脊髄反射的にこういうテーブル構成が採用されるのを見かけます
「記事を作成するユーザーは一人なんだからこれで問題ないのでは?何が言いたいの?言いがかり?そういうの人として恥ずかしくない?」と思われるかもしれませんが、後々サービスの性質が変わって
複数ユーザーで記事を共同作成できる
というユースケースが加わった時には中間テーブルを新規作成して既存データを移し替えるような本番DBのマイグレーション作業が必要になります
最初から中間テーブルにしておくパターン
もしauthorという中間テーブルを作ってarticle_idにunique制約をつけておけば...
テーブル構成は異なりますが先ほどと同じように一対多の関係が多対多テーブルで実現できます。同じarticle_idはauthorテーブルに複数存在できないので、articleに紐づくuser_idは必ず1つであることが保証されます
こうしておけば後々複数ユーザーで記事を共同作成できる
というユースケースが増えた時、DB側で必要な作業はunique制約を外すだけなので非常に楽です
そんな頻繁に一対多が多対多になります?
今回の例だと実感が湧かないかもしれませんが実際サービスを開発していて当初は一対多の関係だった情報が多対多に変化する状況は(個人的に)それなりによく起きるように思います
「A has many B」というユースケースに直面して脊髄反射でuser_idをarticleテーブルが持つような設計を考えたら、ふと立ち止まって企画担当者に「これ将来的に複数ユーザーがarticleを共同作成する事ってあり得ます?」と質問するキッカケにしてみては如何でしょう?意外と「あ、それ次のエンハンスでやろうと思ってます」と言われたり「・・・それ面白いな、やってみようか」となるかもしれません。DB設計を開発のための工程に留めず、企画者にとっても盲点だった新たな仕様に気づくチャンスとして捉えてみると良いのではないでしょうか。
特に新規事業で仮説検証を繰り返しているフェーズではそのタイミングでのパフォーマンスより素早く変更できることが重視されることもあると思うので、デメリットも理解しつつ手札の一つとして持っておいて損はない気がします。あとNULLが嫌いな人が喜びます!
最初から中間テーブルを作っておく代表的なデメリット
アプリケーションで扱いづらい
user_idがarticleに含まれている状態(かつnot null)であれば基本的にarticleには必ずuserが紐づいて取得できることが保証されているのでアプリケーション側で扱いやすいのですが、大体のORMでは中間テーブルを経由するとarticle内にuserの配列が含まれた形で返ってくると思うので、配列長のチェックと空配列だった時の処理を毎回記述する必要があり、ちょっと手間です
余計なデータ量が増える
一個テーブルが増えるので
余計なjoinが増える
一個テーブルが増えるので
親がいなければ子は存在できない、は本当か
「テーブル間に親子関係があると子だけ先に作成できなくて困ることがある」と聞くこともありますがMySQLやPostgreSQLなど代表的なサービスではNULLABLEな外部キー制約を作成できるので、この要因はあまり中間テーブルを作るかどうかには関係ない気がします
昔はNULLが含まれるとインデックスが効かない的な話もあったようですが、最近はNULLもNULLという値(と呼ぶか適切かは分かりませんが)としてインデックスに含まれるのでちゃんとインデックスが使われます
Discussion