正規化とは一言で説明すると「データを効率的に格納するための方法」です。 データの重複をなくし整合的にデータを取り扱えるよう、一定のルールに基づいて変形し、利用しやすくすることが正規化を行う目的です。
正規化には第1、第2、第3正規化などさまざまな種類が存在し、それぞれ正規化するための手順があります。
それらについて深堀していく前に、このページでは、正規化を行う上で最も基本的な以下の2つについて説明していきます。これらの考え方はとても重要です。
- 主キーの定義(情報の特定)
- データの一元管理(情報の分割)
例えば、以下の社員テーブルがあったとします。
名前 | 住所 | 電話番号 |
---|---|---|
鈴木 | 東京都大田区 | 090-XXXX-XXXX |
佐藤 | 東京都台東区 | 090-XXXX-XXXX |
松本 | 東京都中央区 | 090-XXXX-XXXX |
この社員テーブルですが、一見問題ないように見えますが、実は大きな問題を含んでいます。
主キーの定義(情報の特定)
上記した社員テーブルには、現状、同姓同名の社員が存在しないため社員の名前から住所や電話番号を調べることができます。しかし、もし同姓同名の社員が入社してしまうと、名前からでは住所や電話番号を調べることができなくなってしまいます。
名前 | 住所 | 電話番号 |
---|---|---|
鈴木 | 東京都大田区 | 090-XXXX-XXXX |
佐藤 | 東京都台東区 | 090-XXXX-XXXX |
松本 | 東京都中央区 | 090-XXXX-XXXX |
鈴木 | 東京都杉並区 | 090-XXXX-XXXX |
1行目と4行目の「鈴木」さんが同姓同名です。この場合、名前の「鈴木」で検索したら、2行該当し、行を特定できません。
この問題を解決するには、社員のデータに依存しないユニーク(一意)な値を用意する必要があります。ここでは新たに「社員番号」という列を作成します。
社員番号 | 名前 | 住所 | 電話番号 |
---|---|---|---|
1 | 鈴木 | 東京都大田区 | 090-XXXX-XXXX |
2 | 佐藤 | 東京都台東区 | 090-XXXX-XXXX |
3 | 松本 | 東京都中央区 | 090-XXXX-XXXX |
4 | 鈴木 | 東京都杉並区 | 090-XXXX-XXXX |
社員番号には社員一人ひとりに異なる番号を付けます。これでももし同姓同名の社員が入社しても、社員番号で検索すれば、問題なく住所や電話番号を調べることができます。
このように、登録されている情報(レコード)を一意に特定できる項目を「主キー」と呼びます。
もし、社員テーブルに社員番号列(主キー)がなければ、一人の情報を調べるにも、すべての行を確認する必要があります。なぜなら、同姓同名の社員がいるかもしれないからです。社員が数十人ならそれでも良いかもしれませんが、何万人もいるような場合、それでは大変です。
上記テーブルのように、データには「名前」や「住所」「電話番号」などの「調べる対象のデータ」と、それ以外に「調べるために使われるデータ」があるということを覚えておきましょう。
データの一元管理(情報の分割)
一元管理とは、「ひとまとめにして統合的に管理すること」です。つまり、バラバラな情報を一箇所で管理するということです。例えば以下のような社員テーブルがあったとします(上記の社員テーブルに「部門名」列を加えています)。
社員番号 | 名前 | 住所 | 電話番号 | 部門名 |
---|---|---|---|---|
1 | 鈴木 | 東京都大田区 | 090-XXXX-XXXX | 営業部 |
2 | 佐藤 | 東京都台東区 | 090-XXXX-XXXX | 開発部 |
3 | 松本 | 東京都中央区 | 090-XXXX-XXXX | 開発部 |
4 | 鈴木 | 東京都杉並区 | 090-XXXX-XXXX | 営業部 |
一見すると特に問題ないようなテーブルに見えますが、ここにも大きな問題が含んでいます。例えば、もし、「部門名」が変更になったら、このテーブルをどのように更新すれば良いでしょうか。その部門に所属している社員のレコード(行)すべてを更新することになります。
この例の場合、社員が4人なので該当行全てを更新することは問題ないかいもしれませんが、仮に社員が1万人以上いる場合は、大変です。
社員を一意に特定する場合は「社員番号」列を増やすことで問題を解決しました。ここでも同じように、新しく「部門番号」を作成してみます。その際、部門番号と部門名が同じ社員テーブルに入っていても何も変わらないので、テーブルを2つに分割します。
社員テーブル社員番号 | 名前 | 住所 | 電話番号 | 部門番号 |
---|---|---|---|---|
1 | 鈴木 | 東京都大田区 | 090-XXXX-XXXX | 10 |
2 | 佐藤 | 東京都台東区 | 090-XXXX-XXXX | 20 |
3 | 松本 | 東京都中央区 | 090-XXXX-XXXX | 20 |
4 | 鈴木 | 東京都杉並区 | 090-XXXX-XXXX | 10 |
部門番号 | 部門名 |
---|---|
10 | 営業部 |
20 | 開発部 |
このようにテーブルを2つに分割し、それぞれに主キーとなる列(この例では、「社員番号」と「部門番号」列)を追加することで、
効率よくデータを格納することができます。
例えば、部門名を「開発部」から「システム開発部」に変更します。テーブルを2つに分割する前には、社員テーブルからすべてのレコードから該当行を探し更新する必要がありましたが、分割したことで部門テーブルの「部門名」列を1箇所だけ更新すれば更新作業は完了します。
この例で出てきたようなテーブルとテーブルの紐付けを「関係(リレーション)」と言います。RDBMSではこのように格納するデータを正規化し、テーブル間の関係を定義することで膨大な量のデータを管理します。
データは参照されるだけでなく更新されることも検討したうえで「欲しいとき」に「欲しいデータ」を「欲しい状態」で、取り出せるようにしておくことが正規化と基本的な考え方です。