データベースの設計を改善!3NFとBCNFの実践的な使い分け

2024-04-02

3NFとBCNFの違い:分かりやすく解説

リレーショナルデータベースは、情報を表形式で保存するデータベースです。エクセルのようなイメージです。

データベース正規化は、データベースを効率的に管理するために、データを整理する規則です。本棚の本を整理整頓して、必要な情報を見つけやすくするようなイメージです。

3NFBCNFは、データベース正規化の規則のうち、よく使われる2つのレベルです。

3NFは、以下の3つの条件を満たす必要があります。

  1. すべての属性が主キーに部分的に依存している
  2. 主キー以外の属性は、遷移的依存をしていない

決定とは、ある属性の値が決まれば、他の属性の値も決まってしまう関係のことです。

推移的依存とは、ある属性が別の属性に依存し、その別の属性がさらに別の属性に依存している関係のことです。

推移的閉包とは、ある属性が直接的または間接的に依存しているすべての属性の集合のことです。

3NFとBCNFの違い

3NFは、主キー以外の属性が、主キーに直接的に依存しているかどうかで判断します。

BCNFは、3NFよりも厳格な規則です。

以下の表は、社員情報データベースです。

社員番号名前部署役職給与
1山田太郎営業部営業30万円
2佐藤花子経理部経理25万円
3田中一郎開発部開発40万円

この表は、3NFですが、BCNFではありません。

理由

  • 属性役職は、属性部署決定されています。

つまり、属性給与は、属性部署推移的に依存しています。

BCNFにするために

この表をBCNFにするためには、以下の2つの方法があります。

  1. 表を分割する
  2. 属性給与部分キーにする

表を分割すると、以下の2つの表になります。

社員情報表

社員番号名前部署
1山田太郎営業部
2佐藤花子経理部
3田中一郎開発部

役職情報表

部署役職給与
営業部営業30万円
経理部経理25万円
開発部開発40万円

属性給与部分キーにすると、以下のようになります。

社員番号名前部署役職給与
1山田太郎営業部営業30万円
2佐藤花子経理部経理25万円
3田中一郎開発部開発40万円

補足

  • データベース正規化には、3NFとBCNF以外にも、さまざまなレベルがあります。
  • データベース正規化は、データ



# 社員情報データベース

class Employee:
    def __init__(self, employee_id, name, department, position, salary):
        self.employee_id = employee_id
        self.name = name
        self.department = department
        self.position = position
        self.salary = salary


# 部署情報データベース

class Department:
    def __init__(self, department_id, name):
        self.department_id = department_id
        self.name = name


# 役職情報データベース

class Position:
    def __init__(self, position_id, name, salary):
        self.position_id = position_id
        self.name = name
        self.salary = salary


# サンプルデータ

employees = [
    Employee(1, "山田太郎", "営業部", "営業", 300000),
    Employee(2, "佐藤花子", "経理部", "経理", 250000),
    Employee(3, "田中一郎", "開発部", "開発", 400000),
]

departments = [
    Department(1, "営業部"),
    Department(2, "経理部"),
    Department(3, "開発部"),
]

positions = [
    Position(1, "営業", 300000),
    Position(2, "経理", 250000),
    Position(3, "開発", 400000),
]

BCNFのサンプルコード

# 社員情報データベース

class Employee:
    def __init__(self, employee_id, name, department_id, position_id):
        self.employee_id = employee_id
        self.name = name
        self.department_id = department_id
        self.position_id = position_id


# 部署情報データベース

class Department:
    def __init__(self, department_id, name):
        self.department_id = department_id
        self.name = name


# 役職情報データベース

class Position:
    def __init__(self, position_id, name, salary):
        self.position_id = position_id
        self.name = name
        self.salary = salary


# サンプルデータ

employees = [
    Employee(1, "山田太郎", 1, 1),
    Employee(2, "佐藤花子", 2, 2),
    Employee(3, "田中一郎", 3, 3),
]

departments = [
    Department(1, "営業部"),
    Department(2, "経理部"),
    Department(3, "開発部"),
]

positions = [
    Position(1, "営業", 300000),
    Position(2, "経理", 250000),
    Position(3, "開発", 400000),
]

解説

3NFのサンプルコードでは、Employeeクラスには、department属性とposition属性があります。

これらの属性は、employee_id属性に直接的に依存しています。

これらの属性は、employee_id属性ではなく、department属性とposition属性に依存しています。




3NFとBCNFを満たすその他の方法

属性の追加

BCNFを満たすために、属性給与部分キーにする方法以外にも、属性部署役職の組み合わせを主キーにする方法があります。

この方法では、以下のようになります。

社員番号名前部署役職給与
1山田太郎営業部営業30万円
2佐藤花子経理部経理25万円
3田中一郎開発部開発40万円

属性の削除

3NFを満たすために、属性役職を削除する方法があります。

社員番号名前部署給与
1山田太郎営業部30万円
2佐藤花子経理部25万円
3田中一郎開発部40万円

冗長性の許容

例えば、以下の表は、3NFを満たしていませんが、冗長性を許容することで、BCNFを満たすことができます。

社員番号名前部署役職給与
1山田太郎営業部営業30万円
2佐藤花子経理部経理25万円
3田中一郎開発部開発40万円
4高橋二郎営業部営業30万円

database relational-database database-normalization


【保存容量を節約】小数点列よりも整数型で金額を格納するメリット

SQLデータベースで金額を小数点列に格納する場合、精度とスケールという2つの重要な概念を理解する必要があります。これらの設定は、金額データの正確性と効率的な保存に影響を与えます。精度は、小数点を含む数値全体の長さを表します。例えば、精度が10の場合、数値は9桁の整数部と1桁の小数部を持つことができます。...


開発者向け:安全なパスワード管理のためのライブラリ

ここでは、データベースにパスワードを安全に保存するためのベストプラクティスをいくつか紹介します。パスワードをハッシュ化するパスワードをそのままデータベースに保存することは絶対に避けてください。代わりに、ハッシュ関数を使用してパスワードを不可逆的に変換してから保存する必要があります。ハッシュ関数は、パスワードをランダムな文字列に変換し、元のパスワードを復元することは非常に困難になります。...


NOT NULL制約の真実とは?データベース設計におけるメリット・デメリット・代替手段を徹底解説

メリットデータ整合性の向上:制約違反の検出:パフォーマンスの向上:データ型の一貫性:データモデリングの制約:ディスク領域の使用増加:アプリケーションロジックの複雑化:データベースにおける全列NOT NULL制約の設定は、メリットとデメリットを慎重に比較検討した上で判断すべきです。データの整合性と信頼性を重視する場合は有効な手段ですが、データモデリングの制約、ディスク領域の使用増加、アプリケーションロジックの複雑化などのデメリットも考慮する必要があります。...


【初心者向け】SQLiteデータベースでGROUP BYクエリを実行して集計結果を取得する方法

このチュートリアルでは、PHPを使用してSQLiteデータベースに対してGROUP BYクエリを実行し、各グループの行数を取得する方法を説明します。前提知識このチュートリアルを理解するには、以下の知識が必要です。PHPの基本的な構文SQLiteデータベースの操作方法...


MongoDBデータベースの名前変更:直接的な方法と間接的な方法

MongoDB 4.0以降では、renameDatabaseコマンドを使用してデータベース名を直接変更できます。このコマンドを実行すると、old_db_nameデータベースの名前がnew_db_nameに変更されます。注意事項:renameDatabaseコマンドは、4.0より前のバージョンのMongoDBでは使用できません。...