なぜ、データベースを正規化するのか。正規化のメリットについてソースコードレベルで考えてみる(第一正規化)
正規化のメリットについてソースコードレベルで考えてみる
DB設計をする際、あたりまえのように正規化していたのですが、
「なぜ正規化するか」についてはあまり良くわかっていませんでした。
調べると
正規化の理論は、 データの冗長性を排除し、 更新時の整合性を維持しやすくすることを目指しています。
とあるのですが、抽象的でイマイチよくわかりません。
そこで今回は、
正規化した場合としなかった場合を、
仕様変更時にどれだけ大変か
という観点で比較してみました。
実験
「RPGの主人公がアイテムを3つだけ持つことができる」
という仕様でDB設計を行います。
また、主人公の情報とアイテムの情報をviewファイルに書き出すことにします。
A. 正規化をしなかった場合
DB(Heroテーブル)
# | 物理名 | 論理名 |
---|---|---|
1 | id | id |
2 | 名前 | name |
3 | レベル | level |
4 | アイテム1の名前 | item1_name |
5 | アイテム2の名前 | item2_name |
6 | アイテム3の名前 | item3_name |
コントローラ
Heroを1人取得しておきます。
class HeroController def index @hero = Hero.find(1) end end
view
<%= @Hero.name %> <%= @Hero.age %> <%= @Hero.level %> <%= @Hero.item1_name %> <%= @Hero.item2_name %> <%= @Hero.item3_name %>
仕様変更
このような状態で、
「Heroのアイテムを1つ増やしたい」という仕様変更があると、
* DBのカラムにitem4_nameを増やす * viewファイルにitem4_nameを出力するように修正
という変更が必要となってきます。
今回の場合、1コントローラ1viewなので修正範囲は狭いですが、
このテーブルが多くのコントローラ・viewで参照されている場合修正箇所はどんどん増えます。
またこの修正は、Heroのアイテムを増やすたびに行われます。
-- なんだかおかしなことになってきましたね。
B. 正規化する場合
そこでDBを第一正規化してみます。
第1正規化では、同一の情報のグループが繰り返し出現している部分を分離します。
DB(Hero, Itemテーブル)
Heroテーブル
# | 物理名 | 論理名 |
---|---|---|
1 | id | id |
2 | 名前 | name |
3 | レベル | level |
Itemテーブル
# | 物理名 | 論理名 |
---|---|---|
1 | id | id |
2 | HeroId | hero_id |
3 | アイテム名 | name |
controller
class HeroController def index @hero = Hero.find(1) @items = Item.where(hero_id: 1) end end
view
<%= @Hero.name %> <%= @Hero.age %> <%= @Hero.level %> <%= @items.each do |item| %> <%= item.name %> <% end %>
特徴
正規化されていないテーブルから、
「繰り返しが発生しているデータ(Item)」
「発生していないデータ(Hero)」
をわけたことにより、
繰り返しが発生している部分を、eachで回して処理することができるようになりました。
よって、アイテムが1つ増えてもDBやソースコードを修正する必要はありません。
おまけ
以下のようなときは正規化する必要はありません。
個数が変わらないことが保証されているデータ
例えば、人間のパーツをDBで管理することを例として考えてみましょうか。
人間は肺という臓器を2個持っています。腎臓も然り。
この場合、よほどのことがない限り3個以上にはならないので、
別テーブルに分ける必要はありません。
…変な例で失礼しました。