データベース 設計
観光地紹介サービスを作るの要件を読み取り、サービスに必要なテーブルを設計します。
なお、ユーザー登録に必要なテーブルは Laravel が生成するものを利用するため、設計する必要はありません。
テーブルを設計する
要件をもとに、データを分類してみましょう。
新規登録画面で考えてみましょう。
まず、登録するデータを列挙します。
- 観光地名
- 観光地画像
- 住所
- サイト URL
- 電話番号
- 紹介文
次に、それぞれのデータをどういう形で保存するのかを考えます。
- 観光地名
- 文字列
- 観光地画像
- ファイルを BLOB として保存?
- ファイルのパスを文字列で保存?
- 履歴はどうする?
- 住所
- 文字列
- 都道府県や市町村、番地や郵便番号は一緒に登録していいの?
- サイト URL
- 任意登録なので、入力されていない場合は何を保存するのか?
- 電話番号
- どういう形式で保存するのか?
000-0000-0000
とか00000000000
とか
- どういう形式で保存するのか?
- 紹介文
- 最大文字数は何文字に設定するか
データの持ち方が決まったら、今度はデータを表で表現できるかを確認します。
大雑把に定義すると、
- 行と列がある
- 列には名前(データの項目名)が付けられている
- ヘッダー以外の行には列名に対応したデータが設定されている
- 1セル(行列が交わるマス目)につき1つのデータが設定されている
になると思います。
では、新規登録画面のデータを表で表現してみます。
id | 観光地名 | 画像 | 住所 | URL | 電話番号 | 紹介文 |
---|---|---|---|---|---|---|
1 | 貴船神社 | image.png, image2.png | 京都府京都市左京区 | http://kifunejinja.jp/ | 075-741-2016 | とても綺麗なところです |
上記は画像列が1セルに対して1つのデータという条件を満たしていません。
ではどうすればいいでしょうか。
画像列以外のデータが全く同じな行を作ってみます。
id | 観光地名 | 画像 | 住所 | URL | 電話番号 | 紹介文 |
---|---|---|---|---|---|---|
1 | 貴船神社 | image.png | 京都府京都市左京区 | http://kifunejinja.jp/ | 075-741-2016 | とても綺麗なところです |
2 | 貴船神社 | image2.png | 京都府京都市左京区 | http://kifunejinja.jp/ | 075-741-2016 | とても綺麗なところです |
これで表としては正しくなりました。
ですが、このままでは問題があります。
例えば、URL が http
から https
に変わったとします。
当然登録されている URL も変更しなければいけません。
ここで問題になるのは、情報としては同一なのにも関わらず、2行変更しなければ整合性を保てないところです。
この例では2行だけですが、画像履歴がどんどん増えていった場合、またそれが複数データに及んだ場合、管理が煩雑になるだけではなく、パフォーマンスも悪くなってしまいます。
この問題を解決するためにはどうすればいいでしょうか?
解決方法としては、画像履歴テーブルを作るという方法が簡単かつ妥当でしょう。
観光地テーブル
id | 観光地名 | 住所 | URL | 電話番号 | 紹介文 |
---|---|---|---|---|---|
1 | 貴船神社 | 京都府京都市左京区 | http://kifunejinja.jp/ | 075-741-2016 | とても綺麗なところです |
画像履歴テーブル
id | 画像 |
---|---|
1 | image.png |
2 | image2.png |
最新画像テーブル
id | spot_id (観光地テーブルの ID) | history_id (履歴テーブルの ID) |
---|---|---|
1 | 1 | 2 |
画像履歴テーブルにはアップロードされた画像の履歴を持ち、観光地テーブルから画像列を削除、最新画像を保存するテーブルを作成して、観光地と画像履歴の識別子をペアで保存することで、データがいくら変更されようが、1行のみの更新で済むようになりました。
また、画像データが10増えようが、100増えようが、観光地テーブルには影響は出ません。
このように、データの一貫性の維持と効率的なデータアクセスを可能にする設計を正規化
と呼びます。
正規化にもいくつか段階があり、第5正規化までありますが、特殊な場合を除き、第3正規化までで必要十分です。
上記の例では、第1正規化を行いました。
この例を参考に、サービスに必要なテーブルを設計してみましょう。