Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】NORMALIZATION

2025年10月01日に「Dev.to」が公開したITニュース「NORMALIZATION」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

データベース正規化は、データの重複をなくし、不整合を防ぐ技術だ。1NF, 2NF, 3NFの順に進め、データを適切に分割することで、情報の追加・更新・削除時に起こる問題(アノマリー)を解決し、効率的なデータベースを設計する。

出典: NORMALIZATION | Dev.to公開日:

ITニュース解説

データベースを設計する際、データが整理されていないと様々な問題が発生する。この問題を解決し、データの整合性を保ち、効率的に管理するための手法が「データベースの正規化」である。

たとえば、学生がどのコースを受講し、どの講師が担当しているかを管理するシステムを考えてみる。もし、次のような単一のテーブルで全ての情報を管理しようとすると、複数の問題に直面する。

初期のテーブルには「StudentID」「StudentName」「CourseID」「CourseName」「Instructor」「InstructorPhone」といった列があると想定する。このテーブルには、学生「Arjun」が「DBMS」と「Data Mining」の2つのコースを受講している場合、Arjunの学生情報(StudentID, StudentName)とコース情報、講師情報がそれぞれの行で繰り返して記載されることになる。一見問題ないように見えるが、ここには複数の「アノマリー(異常)」が潜んでいる。

一つ目の問題は「挿入アノマリー」である。これは、新しいコース情報をデータベースに追加したい場合、そのコースを履修する学生が一人もいないと追加できないという問題である。もし「AI」という新しいコースが作られたが、まだ誰も履修していない場合、このコースを登録するためには架空の学生情報を用意するか、学生が履修するまで登録を待たなければならない。これはデータの管理上、非常に不便である。

二つ目の問題は「更新アノマリー」である。例えば、Dr. Kumarの電話番号が変更になった場合を考えてみる。Dr. Kumarが教えているコースを複数の学生が受講しているため、Dr. Kumarの情報はデータベース内の複数の行にわたって存在している。電話番号を変更するには、これら全ての行を手作業で探し出し、一つずつ更新する必要がある。もし一つでも更新し忘れると、データベース内でDr. Kumarの電話番号が異なる情報として複数存在することになり、データの整合性が失われる。

三つ目の問題は「削除アノマリー」である。もし学生Priyaが「DBMS」コースの履修を取りやめ、その情報をデータベースから削除した場合、Priyaが履修している唯一のコースがDBMSだったとすると、DBMSコースに関する全ての情報(コース名、担当講師、講師の電話番号など)がデータベースから消えてしまう。たとえ他の学生がDBMSを履修していたとしても、その情報を保持している行が残っていなければ、コースそのものの情報まで失われてしまうのである。

これらのアノマリーを解消し、データ管理を効率化するために、データベースの正規化が必要となる。正規化は主に「第一正規形(1NF)」「第二正規形(2NF)」「第三正規形(3NF)」の三段階で進められることが一般的である。

第一正規形(1NF)

第一正規形のルールは「繰り返しグループを排除し、アトミックな値を保証する」ことである。アトミックな値とは、それ以上分割できない単一の情報を指す。例えば、「住所」という情報が「都道府県」「市区町村」「番地」に分割できる場合、それはアトミックではない。しかし、ニュース記事の例の初期テーブルは、全ての列が既にアトミックな値を持っているため、この段階ではテーブルの構造自体は大きく変わらない。つまり、単一のセルに複数の値が入っていたり、同じ情報が別の列で繰り返されたりするような状況は避けられている。しかし、挿入、更新、削除のアノマリーは依然として残ったままである。

第二正規形(2NF)

第二正規形のルールは「部分関数従属を排除する」ことである。これは、テーブルの主キー(レコードを一意に識別するための列、または列の組み合わせ)が複合主キーである場合に問題となる。複合主キーとは、複数の列を組み合わせて主キーとするものである。

ニュース記事の例では、初期のテーブルでStudentIDとCourseIDの組み合わせが複合主キーとして機能していると考えると、「CourseName」「Instructor」「InstructorPhone」といったコースに関する情報は、「StudentID」と「CourseID」の両方に依存しているわけではなく、「CourseID」のみに依存していることがわかる。例えば、CourseNameは特定のCourseIDが決まれば一意に決まるが、どの学生が履修しているかは関係ない。これを「部分関数従属」と呼ぶ。

この部分関数従属を排除するために、テーブルを分割する。具体的には、学生情報(StudentID, StudentName)を持つ「Student」テーブル、コース情報(CourseID, CourseName, Instructor, InstructorPhone)を持つ「Course」テーブル、そして学生とコースの関連(StudentID, CourseID)のみを持つ「Enrollment(履修)」テーブルの三つに分割する。

StudentテーブルではStudentIDを主キーとし、CourseテーブルではCourseIDを主キーとする。EnrollmentテーブルではStudentIDとCourseIDの組み合わせを複合主キーとし、それぞれをStudentテーブルとCourseテーブルの外部キー(FOREIGN KEY)として参照させる。これにより、特定のコース情報が特定の学生の存在に依存することはなくなり、更新アノマリーや削除アノマリーの一部が解消される。例えば、Dr. Kumarの電話番号が変更されても、Courseテーブルの該当する行を一度更新するだけで済む。また、新しいコースを学生が履修していなくてもCourseテーブルに登録できるため、挿入アノマリーも解消される。

しかし、まだ問題が残っている。Courseテーブルの中で「InstructorPhone」が「Instructor」に依存しているという状況である。これは「推移的関数従属」と呼ばれる。

第三正規形(3NF)

第三正規形のルールは「推移的関数従属を排除する」ことである。これは、主キーではない列(非キー列)が、別の非キー列に依存している状態を指す。ニュース記事の例では、Courseテーブルにおいて「InstructorPhone」は「CourseID」に直接依存するのではなく、「Instructor」という非キー列に依存している。つまり、「Instructor」が決まれば「InstructorPhone」も決まるという関係である。

この推移的関数従属を解消するため、さらにテーブルを分割する。Courseテーブルから講師に関する情報(Instructor, InstructorPhone)を切り離し、独立した「Instructor」テーブルを作成する。Instructorテーブルには「InstructorID」「InstructorName」「InstructorPhone」といった列を持ち、InstructorIDを主キーとする。

そして、元のCourseテーブルを「Course3NF」として再定義し、「CourseID」「CourseName」に加えて、Instructorテーブルの主キーである「InstructorID」を外部キーとして持たせる。これにより、InstructorPhoneはInstructorテーブルの中でInstructorNameに直接依存する形となり、Courseテーブルからは推移的関数従属が完全に排除される。

最終的に、ニュース記事の例のデータベースは「Student」「Instructor」「Course3NF」「Enrollment」の四つのテーブルに分割されることになる。

このように正規化を進めることで、データの冗長性(重複)が大幅に削減され、挿入、更新、削除のアノマリーはほぼ解消される。それぞれの情報が適切なテーブルに格納され、データの整合性が高く保たれるため、データベース全体の信頼性が向上し、メンテナンスも容易になる。

もちろん、情報が必要な際にはこれらの分割されたテーブルを結合(JOIN)することで、元の情報、例えば「どの学生がどのコースを受講し、どの講師が担当しているか、その講師の電話番号は何か」といった情報を効率的に取り出すことが可能である。データ量が多いデータベースでは、このように正規化された設計がシステムの安定性と性能に大きく貢献する。

関連コンテンツ