データベース(以下DB)のテーブル設計についてです。
MySQLの前提ですが、他DBでも大体は共通しているかと思います。
IDは原則付ける
idカラムは全てのテーブルに原則付けます。
ID Required としてアンチパターンに上げられて賛否両論ありましたが、原則ある方がよいです。
なくてよいのは多対多リレーションの中間テーブルくらいでしょうか。(なくてよいパターンがあるという意味ではID Requiredはアンチパターンといえなくもないですが。)
とはいえ、つけて損が実感できるレベルってある程度の規模なので、この記事を読んでいるくらいのレベル感であれば迷ったらidつけるでいいかと思います。
形式はUUIDです。
Auto_Increment(オートインクリメント:以下AI)は昔はよく使いましたが今では基本使いません。
AIは順番にカウントアップされていくので「今作成したアイテムがID1000だからまだあんまりサービス使われてないな」「ID50ということは49もあるはず」など余計な情報を与えてしまいます。
セキュリティ的にもよくありませんのでUUIDを使いましょう。
例外的に正規化できるけれどあえてしないとき、例えば「userテーブルが100カラムを超えてでかすぎるので、SNS系の項目は別テーブルに分けよう」というときであればuser_idを主キーとしたidカラムのないテーブルも作成することがありますが、ほぼありません。
複合主キーとなるようなテーブルもidカラムは作成して主キーにし、複合ユニークキーにしてしまう方がお勧めです。
1項目だけでレコードを絞り込めるのは色々と取り回しがしやすいです。
とはいえこのあたりは正直ケースバイケースで特にDBの種類によっては複合主キーでないとできないケースもあるかと思います。
リソースならidカラムもほしいけれど前述の通り中間テーブルならいりません。
また「このテーブルってIDあったっけ?」「このテーブルはID付けるかどうか」というのを考えなくていいのは楽ですし一番困る「ID付けとけばよかった」のケースがないのは安心です。
created_atとupdated_atは付ける
あるといざというときに調査が楽です。
created_atは CURRENT_TIMESTAMP、
updated_atは CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
を設定しておきます。(MySQLの場合)
idとは違い、こちらは中間テーブルであろうとなんであろうと設定するのが推奨です。
created_atとupdated_atの値が違えば生成の後にどこかで更新されたことがわかりますし、
同時に更新されるはずのデータでupdated_atの日時がずれていれば片方の更新が失敗している可能性がでてきます。
アクセスログやsyslogと照らし合わせるようなこともあります。
statusも大体つける
statusもだいたい付けます。
中間テーブルなど付けないこともありますが、個人的には付けるか付けないか迷ったらとりあえず付けます。
とはいえ、何千万行もいかないようなレコード数であればALTER TABLEもすぐ終わるので「一瞬止まるけど大丈夫」というケースなど、規模が大きくなければ必要になってからつけるで十分です。
intにしてプログラム側で定数STATUS_AVAILABLE = 0; という設定をしておけばDBの節約になります。
小規模サービスであればSTATUS_AVAILABLE = 'available'; というようにアルファベット入れておく方が追加や削除がしやすく、値見ただけでも意味がわかるので使いやすいです。
どちらにしてもマジックナンバーはよろしくないのでソースコード上に定数を定義しておきましょう。
関連するモデルに定数定義しておくのがおすすめです。
正規化について
テーブル設計は一箇所変更があっただけなら一箇所変更するだけで済むようにというのが基本です。
そうなるようにテーブルを分割することを正規化といいますが、正規化については下記記事がわかりやすかったのでこちらを参照していただければいいかと思います。
https://qiita.com/naoqoo2/items/cdda5fe6f9935a03189d
実際のところ正規化を考えてというよりは感覚で分割しますが、基本はこのようなやり方です。
ちなみに、第5正規化までありますが細かくしすぎるとプログラムで使うときにかなり使いにくくなります。
正規化すればするほどいいというわけではないので第三正規化程度にしておきましょう。
また、テーブル設計はindexが理解できているとより感覚的にわかりやすくなるでしょう。
テーブルを作成する際はindexの設定も必要なのであわせて学習しておきましょう。