設計手順
DBの設計手順をYoutubeの動画を見て学んだ
システムの要件を把握
要件と機能を明確にする
テーブルの概要設計(ラフスケッチ)
シナリオを考えながら思いつく限りのテーブルとカラムを日本語(慣れてきたら最初から英語名)で作る
これExcelだとやりやすいらしい
テーブルの詳細設計(最終調整)
ここからMysqlWorkbenchを使うといいらしい
日本語を英語に変換
日本語名を「論理名」、英語名を「物理名」というらしい
命名規則
- 半角英数、アンダースコア
- テーブル名は複数形、カラム名は単数形
カラムに型を付ける
varchar(255)
は大事。256以上だとインデックスが貼れなくなるらしい。
どのテーブルにも、
id
: プライマリキー、INT型 Auto Increment、プリフィックス不要
created_at
: datetime型
updated_at
: datetime型
を追加する
ER図を書きながら正規化
リレーションを貼っていく。
1:N
の関係のものは、N
側に外部キーを持たせる。テーブル名の単数形_id
みたいな形にする。
制約条件やインデックスをつける
インデックス: 検索のキーになるカラムにつける、主キーや外部キーには自動でつくので付けなくてもおk
例えば、名前で検索したい時などで、
name
カラムにつけたりする、これ必要かな?
制約:NOT NULL、ユニークキー(重複しないものにはできるだけ指定する)、外部キー(リレーション先にレコードが存在することを保証する)
正規化
第一正規形
横方向の繰り返しをなくす。横方向に同じカラム名を繰り返さない
ユーザ名 | 商品名 | 単価 | 数量 | 商品名 | 単価 | 数量 | 商品名 | 単価 | 数量 |
---|---|---|---|---|---|---|---|---|---|
A | a | 100 | 1 | b | 120 | 2 | c | 150 | 3 |
↓
ユーザ名 | 商品名 | 単価 | 数量 |
---|---|---|---|
A | a | 100 | 1 |
A | b | 120 | 2 |
A | c | 150 | 3 |
第二正規形、第三正規形
どちらも、縦方向の繰り返しをなくす。(なんか推移従属か完全従属かみたいな違いらしいけど、そんなのどうでもいいらしい)
注文番号 | 注文日 | ユーザ名 | 住所 | 送料区分 | 商品名 | 単価 | 数量 | 合計金額 |
---|---|---|---|---|---|---|---|---|
0001 | 1/4 | ユーザA | 住所A | その他 | 商品a | 100 | 1 | 330 |
0001 | 1/4 | ユーザA | 住所A | その他 | 商品c | 10 | 3 | 330 |
0001 | 1/4 | ユーザA | 住所A | その他 | 商品d | 200 | 2 | 330 |
0002 | 1/4 | ユーザB | 住所B | その他 | 商品b | 50 | 5 | 250 |
0003 | 1/5 | ユーザC | 住所C | 離島 | 商品b | 50 | 1 | 70 |
0003 | 1/5 | ユーザC | 住所C | 離島 | 商品c | 10 | 2 | 70 |
0004 | 1/8 | ユーザB | 住所B | その他 | 商品b | 50 | 5 | 250 |
↓ 1:n
の関係のテーブルに分割する。注文番号をキーとする
注文番号 | 注文日 | ユーザ名 | 住所 | 送料区分 | 合計金額 |
---|---|---|---|---|---|
0001 | 1/4 | ユーザA | 住所A | その他 | 330 |
0002 | 1/4 | ユーザB | 住所B | その他 | 250 |
0003 | 1/5 | ユーザC | 住所C | 離島 | 70 |
0004 | 1/8 | ユーザB | 住所B | その他 | 250 |
注文番号 | 商品名 | 単価 | 数量 |
---|---|---|---|
0001 | 商品a | 100 | 1 |
0001 | 商品c | 10 | 3 |
0001 | 商品d | 200 | 2 |
0002 | 商品b | 50 | 5 |
0003 | 商品b | 50 | 1 |
0003 | 商品c | 10 | 2 |
0004 | 商品b | 50 | 5 |
↓
まだユーザ情報と商品情報で縦の繰り返しがあるから、1:N
の関係にテーブルを分割してやる。(第2正規形)
送料区分も縦の繰り返しがあるから、1:N
の関係にテーブルを分割してやる。(第3正規形)
注文番号 | 注文日 | ユーザID | 合計金額 |
---|---|---|---|
0001 | 1/4 | Y0001 | 330 |
0002 | 1/4 | Y0002 | 250 |
0003 | 1/5 | Y0003 | 70 |
0004 | 1/8 | Y0002 | 250 |
注文番号 | 商品ID | 数量 |
---|---|---|
0001 | S0001 | 1 |
0001 | S0003 | 3 |
0001 | S0004 | 2 |
0002 | S0002 | 5 |
0003 | S0002 | 1 |
0003 | S0003 | 2 |
0004 | S0002 | 5 |
ユーザID | ユーザ名 | 住所 | 送料区分ID |
---|---|---|---|
Y0001 | ユーザA | 住所A | 01 |
Y0002 | ユーザB | 住所B | 01 |
Y0003 | ユーザC | 住所C | 02 |
商品ID | 商品名 | 単価 |
---|---|---|
S0001 | 商品a | 100 |
S0002 | 商品b | 50 |
S0003 | 商品c | 10 |
S0004 | 商品d | 200 |
送料区分ID | 送料区分 |
---|---|
01 | その他 |
02 | 離島 |
注意
楽に扱えるのかどうかを考えながら、マスタとして切り出していく。
正規化しすぎるとアプリケーションコードに落とし込む時につらい。
一対一のものはメインに入れちゃう。
リレーション
N:N
の関係のテーブルがあったら、必ず中間テーブルを持たせる。
中間テーブルにはリレーション以外の情報を極力持たせない。持たせても日時関連くらい。