MySQL: MySQL Database Design and Normalization Theory

Last updated: 2026-08-26

Good database design is the cornerstone of a system’s success—poor design can lead to endless problems down the road.

This lesson covers the theory and practice of database design.

1. What You'll Learn



2. Design Process

100%
graph TB
    A[Requirements Analysis] --> B[Conceptual Design ER Diagram]
    B --> C[Logical Design Table Structure]
    C --> D[Physical Design Index/Partition]
    D --> E[Implementation and Deployment]
    E --> F[Operations and Maintenance Optimization]


3. Paradigm Theory

Paradigm Requirements Example
1NF Fields cannot be further divided A phone number cannot have multiple entries
2NF Eliminating partial dependencies Non-primary key fields are fully dependent on the primary key
3NF Eliminate transitivity Non-primary key fields cannot depend on other non-primary key fields
BCNF Every determining factor is a candidate key A stricter form of 3NF

▶ Example: 3NF Design

Output:

TEXT 📖 Display only
id | customer_id | total_amount
---+--------------+-------------
1  | 101          | 299.99
SQL
-- Violation of 3NF (Department name depends on dept_id, not directly on employee id)
CREATE TABLE employees_bad (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    dept_id INT,
    dept_name VARCHAR(50)  -- Transitive dependency
);

-- ✅ Comply with 3NF
CREATE TABLE departments (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    dept_id INT,
    FOREIGN KEY (dept_id) REFERENCES departments(id)
);

Output:

TEXT 📖 Display only
Query executed successfully

▶ Example: Anti-Paradigm Design for Performance

Output:

TEXT 📖 Display only
Query executed successfully
SQL
-- Normalized design: requires JOIN to get order total
CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT,
    order_date DATE
);

CREATE TABLE order_items (
    id INT PRIMARY KEY,
    order_id INT,
    product_name VARCHAR(100),
    quantity INT,
    price DECIMAL(10, 2)
);

-- Anti-paradigm: add a total_amount column to avoid real-time calculation
ALTER TABLE orders ADD COLUMN total_amount DECIMAL(10, 2);

-- Now you can query order totals without a JOIN
SELECT id, customer_id, total_amount FROM orders WHERE id = 1;

Output:

TEXT 📖 Display only
Query executed successfully

▶ Example: ER Diagram to Table Structure

Output:

TEXT 📖 Display only
Query executed successfully
SQL
-- From ER diagram to SQL: E-commerce core tables

-- Customers table
CREATE TABLE customers (
    id INT PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL
);

-- Products table
CREATE TABLE products (
    id INT PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10, 2) NOT NULL
);

-- Orders table (relationship: one customer → many orders)
CREATE TABLE orders (
    id INT PRIMARY KEY AUTOINCREMENT,
    customer_id INT NOT NULL,
    order_date DATE NOT NULL,
    FOREIGN KEY (customer_id) REFERENCES customers(id)
);

-- Order items (relationship: one order → many items, one product → many items)
CREATE TABLE order_items (
    id INT PRIMARY KEY AUTOINCREMENT,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);

Output:

TEXT 📖 Display only
id | customer_id | total_amount
---+--------------+-------------
1  | 101          | 299.99


4. Anti-Paradigm Design

Sometimes, for the sake of performance, we deliberately break the rules.

Scenario Anti-paradigm Approach Reason
Frequent JOINs Redundant Fields Fewer JOINs
Statistical Queries Calculated Columns Avoiding Real-Time Calculations
Reports Summary Reports Speed Up Queries


5. Naming Conventions

Best Practices Recommendations Things to Avoid
Table Name snake_case, plural singular, camelCase
Field Name snake_case camelCase, Chinese
Primary Key id userId
Foreign Key table_id customerId
Index idx_table_col table_col_idx


6. ER Diagram Design

100%
erDiagram
    CUSTOMERS ||--o{ ORDERS : places
    ORDERS ||--|{ ORDER_ITEMS : contains
    PRODUCTS ||--o{ ORDER_ITEMS : includes
    CUSTOMERS {
        int id PK
        string name
        string email
    }
    ORDERS {
        int id PK
        int customer_id FK
        decimal amount
        date order_date
    }
    PRODUCTS {
        int id PK
        string name
        decimal price
    }

❓ FAQ

Q Is it necessary to adhere to 3NF?
A In most cases, yes. However, in scenarios with many reads and few writes, it’s acceptable to deviate from the normal form.
Q What data types should be used for the fields?
A Use BIGINT for the primary key, DECIMAL for amounts, TIMESTAMP for dates and times, and VARCHAR for text.
Q Should table names be in the singular or plural?
A We recommend using the plural (users, orders) to indicate "a set of records."
Q Is it necessary to adhere to the three normal forms?
A Not necessarily. In high-concurrency query scenarios, you can deviate from the normal forms; appropriate redundancy can reduce the number of JOINs.
Q What tools can be used for ER diagrams?
A MySQL Workbench (forward/reverse engineering), draw.io (free online tool), and dbdiagram.io (ER diagram generation from code).

📖 Summary


📝 Exercises

  1. Basic Problem (Difficulty: ⭐): Design an ER diagram for a blog system.

  2. Advanced Problem (Difficulty ⭐⭐): Normalize a table in 1NF to 3NF.

  3. Challenge Question (Difficulty: ⭐⭐⭐): Design an e-commerce database that includes tables for users, products, orders, and payments.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏