Schema Design
資料庫 Schema 設計ガイド。Schema 類型、正規化流程と MongoDB 設計規則を網羅。
Schema Types
Relational Model
関連式モデルは最も一般的な資料庫モデルで、テーブル(Table)を使用して資料を組織し、主鍵(Primary Key)と外鍵(Foreign Key)でテーブル間の関係を確立する。
Star Schema
適用例:
- Retail Sales Analysis(小売販売分析)
- Financial Reporting(財務報表)
- Marketing Campaign Analysis(マーケティング活動分析)
- Inventory Management(在庫管理)
Star Schema の特徴:
- 中心は Fact Table(事実表)、度量値を含む(販売額、数量など)
- 周囲は Dimension Tables(維度表)、記述的情報を提供(時間、商品、地域など)
- 構造が単純で、查詢性能が良好
Snowflake Schema
適用例:
- Customer Relationship Management (CRM)
- Healthcare Data Analysis(医療データ分析)
- E-commerce Platform(電商プラットフォーム)
- Supply Chain Management(サプライチェーン管理)
Snowflake Schema の特徴:
- Star Schema の正規化版
- Dimension Tables をさらに多層構造に分割
- 資料冗餘を減少するが、查詢は複雑になる
RDB Design Steps
Step 1: Write a Sentence
保存する資料を一文で記述する:
- Store the customer information and the orders that they made
- Store the car and the showroom that they are located in
- Store the students and the courses they are enrolled in at a specific date
Step 2: Pick Objects From Sentence
文から主要オブジェクトを抽出:
- customer information
- orders
- car
- showroom
- students
- courses
- date
Step 3: Determine Relationship
- Does a customer have many orders, or does an order have many customers?
- Does a car have many showrooms, or does a showroom have many cars?
- Does a student have many courses, or does a course have many students?
Step 4: Create a Diagram
Step 5: Joining Table
Many-to-Many 関係の場合、Joining Table(関連表)を作成する必要がある。
例:Student と Class の関係
誤った方法:
正しい方法:
ER Diagram:
Normalization
正規化は資料をテーブルに整理するプロセスで、資料冗餘を減少し、資料完整性を確保する。
1NF (First Normal Form)
第一正規化:重複値を除去
- Does the combination of all columns make a unique row every single time?
- What field can be used to uniquely identify the row?
2NF (Second Normal Form)
第二正規化:部分相依を除去 / 主鍵の一部にのみ依存する欄位を除去
- Fulfil the requirements of first normal form
- Each non-key attribute must be functionally dependent on the primary key
欄位が主鍵に依存するかを判断:
| 欄位 | PK に依存? | 説明 |
|---|---|---|
| student name | Yes | 異なる学生 ID は異なる学生名を表す |
| fees paid | Yes | 各費用値は単一学生に対応 |
| date of birth | Yes | 生年月日はその学生に特有 |
| address | Yes | 住所はその学生に特有 |
| subject 1~4 | No | 一つの科目に複数の学生が登録できる |
| teacher name | No | 教師名はこの学生に依存しない |
| teacher address | No | 教師住所はこの学生に依存しない |
| course name | No | 課程名は学生に依存しない |
主鍵に依存しない欄位は新しいテーブルに移動:
Subject (subject ID, subject name)Teacher (teacher ID, teacher name, address)Course (course ID, course name)Student (student ID, student name, fees paid, date of birth, address)
Foreign Keys in Tables
自問:
- Does a course have many students, or does a student have many courses?
- Does a teacher have many courses, or does a course have many teachers?
- Does a subject have many students, or does a student have many subjects?
2NF 結果:
3NF (Third Normal Form)
第三正規化:間接相依を除去 / 主鍵以外に相依関係のある欄位を除去
Transitive Functional Dependency(遞移函数相依):
- Column A determines column B
- Column B determines column C
- Therefore, column A determines C
住所を例に:
| address |
|---|
| 3 Main Street, North Boston 56125 |
| 16 Leeds Road, South Boston 56128 |
ZIP code が city、state と suburb を決定する。
Student が address ZIP code を決定し、さらに suburb を決定する。
分割結果:
Address Code (address code ID, ZIP code, suburb, city, state)- Student Table →
(student ID, course ID, student name, fees paid, date of birth, street address, address code ID) - Teacher Table →
(teacher ID, teacher name, street address, address code ID)
3NF ER Diagram:
4NF & BCNF
- 4NF:多値相依(Multi-valued Dependency)を処理
- BCNF (Boyce-Codd Normal Form):複合主鍵はすべて外鍵である必要がある
MongoDB Schema Design
Design Rules
One-to-One
{
"_id": "ObjectId('AAA')",
"name": "Joe Karlsson",
"company": "MongoDB",
"twitter": "@JoeKarlsson1",
"website": "joekarlsson.com"
}One-to-Few (Embedding)
埋め込まれたオブジェクトを個別に読み取ることがほとんどない場合、埋め込みモードを使用する。関連数量は通常 1000 以内。
{
"_id": "ObjectId('AAA')",
"name": "Joe Karlsson",
"addresses": [
{ "street": "123 Sesame St", "city": "Anytown", "cc": "USA" },
{ "street": "123 Avenue Q", "city": "New York", "cc": "USA" }
]
}One-to-Many (Child-Referencing)
例:電商サイトの商品ページ、一つの商品が複数の部品で構成される。
Products Collection:
{
"name": "left-handed smoke shifter",
"manufacturer": "Acme Corp",
"parts": ["ObjectID('AAAA')", "ObjectID('BBBB')", "ObjectID('CCCC')"]
}Parts Collection:
{
"_id": "ObjectID('AAAA')",
"partno": "123-aff-456",
"name": "#4 grommet",
"qty": "94",
"cost": "0.94",
"price": "3.99"
}One-to-Squillions (Parent-Referencing)
時間とともに資料量が成長する場面に適している(システムログ、取引ログなど)。
Host Collection:
{
"_id": "ObjectID('AAAB')",
"name": "goofy.example.com",
"ipaddr": "127.66.66.66"
}Log Collection:
{
"time": "ISODate('2014-03-28T09:42:41.382Z')",
"message": "cpu is on fire!",
"host": "ObjectID('AAAB')"
}Many-to-Many
例:To-Do App、一人のユーザーが複数のタスクを持ち、一つのタスクが複数のユーザーに割り当てられる。
Users Collection:
{
"_id": "ObjectID('AAF1')",
"name": "Kate Monster",
"tasks": ["ObjectID('ADF9')", "ObjectID('AE02')", "ObjectID('AE73')"]
}Tasks Collection:
{
"_id": "ObjectID('ADF9')",
"description": "Write blog post about MongoDB schema design",
"due_date": "ISODate('2014-04-01')",
"owners": ["ObjectID('AAF1')", "ObjectID('BB3G')"]
}