たいていリレーショナルデータベース(RDB)で論理設計を行う際におそらく第三正規化までは行うかと思います。
しかし、条件反射で常に正規化をしようとするとうまく設計できないこともあります。
#ユーザーの注文履歴について考える
ECサイトを作るにあたり、注文履歴を管理するとしましょう。例えば以下のようなテーブルがあるとします。
ユーザーの注文履歴情報
ID | ユーザー名 | 購入日 | 商品名 | 金額 | 販売者 | 配送先 |
---|---|---|---|---|---|---|
1 | ヒロロ開発部長 | 2019/01/01 | iPhone6s | 39,800 | D社 | 東京都新宿区西新宿1-1-1 |
ユーザー情報
ID | ユーザー名 | 配送先 |
---|---|---|
1 | ヒロロ開発部長 | 東京都新宿区西新宿1-1-1 |
商品マスター
ID | 商品名 | 金額 | 販売者 |
---|---|---|---|
1 | iPhone6s | 42,800 | A社 |
2 | iPhone6s | 39,800 | D社 |
3 | iPhone7 | 48,800 | D社 |
この時、「おっ、ユーザーの注文情報にユーザーIDと商品マスターIDを外部キーとしてもたせられるな」と思い、ユーザーの注文情報テーブルを以下のようにします。
ユーザーの注文履歴情報’
ID | ユーザーID | 商品マスターID | 購入日 |
---|---|---|---|
1 | 1 | 2 | 2019/01/01 |
こうすれば問い合わせるときにユーザーIDと商品マスターIDをもとにテーブル結合すればユーザーの注文情報を取得することができます。
しかし、これではあってはならない問題が発生します。
マスター情報を変更すると注文履歴の情報が変わってしまう
例えば、2019/5/28にユーザーが配送先を変更した場合、ユーザー情報のテーブルは以下のようになります。
ユーザー情報'
ID | ユーザー名 | 配送先 |
---|---|---|
1 | ヒロロ開発部長 | 東京都江東区木場1-1-1 |
その場合、注文履歴情報はテーブル結合することを前提としているため、結果的に2019/01/01に購入したときの配送先が変わってしまうことになります。
また、同様に販売者が2019/01/01以降に商品価格を変更した場合、同様に実際に購入したときの金額が変更後の価格に塗り替えられてしまいます。
「商品名だけだと同名のものが多く混在しそうだから商品IDで管理したほうがいいだろう」と考えて安易にこのようにしてしまう可能性があります。十分に検討しないとシステムが甚大な不具合を発生させる危険があります。
どういうものにするかにもよりますが、履歴のようにデータの変更が発生しないものを管理する際は無理に正規化をしないほうがいいです。ただし、購入予定リスト(Amazonでいう「カートにいれているもの」)とかはマスターの変更に伴い、価格なども反映される必要があるので正規化するべきでしょう。
まとめ
このような思考にたどり着くまでに正規化するのはいいですが、それで終わってしまってはいけません。
ちゃんと設計できる人はこのようなことは当たり前に思われるかもしれませんが、常に正規化をするのではなく、アプリケーションの目的をしっかり踏まえて考えるようにしましょう。