Table of Contents

    normalization and denormalization

    RELATIONAL DATA MODELING & SQL

    Normalization and Denormalization

    Learn how normalization organizes relational data to reduce redundancy and prevent modification anomalies, and how deliberate denormalization can improve measured read performance while introducing additional consistency responsibilities.

    Introduction

    A relational database can store the correct information and still have a poor structure. When unrelated facts are combined in one table, the same values are often repeated across many rows.

    Repeated data wastes storage, complicates updates, and creates opportunities for contradictory information.

    Normalization organizes data into related tables so that each important fact has an appropriate and controlled place.

    Denormalization deliberately introduces selected duplication or precomputed data to support specific read-performance requirements.

    Core idea: Normalize first to establish a reliable source of truth. Denormalize later only when measured workload evidence shows that a particular read path needs a different physical structure.

    In your System Design curriculum, Normalization and Denormalization is Topic 5.2 under Relational Data Modeling & SQL. It follows entities and relationships and precedes keys and constraints, ACID, transactions, isolation, indexes, query plans, and connection pools.

    Prerequisites

    # Prerequisite Why It Is Needed
    1 Entities and relationships Normalization depends on identifying distinct entities, attributes, and associations.
    2 Primary and foreign keys Decomposed tables are connected through keys.
    3 Basic SQL The examples use table definitions, joins, inserts, updates, and aggregate queries.
    4 Functional dependencies Normal forms examine how one set of attributes determines another.
    5 Database transactions Denormalized copies often require coordinated updates.
    6 Query-performance basics Denormalization should respond to measured workload and query-plan evidence.

    What Is Normalization?

    Normalization is a systematic process for organizing relational data to reduce unnecessary duplication and prevent insertion, update, and deletion anomalies.

    The process usually decomposes a large relation into smaller related relations based on keys and functional dependencies.

    Normalization Process
    identify facts → identify dependencies → detect anomalies → decompose relations → add keys and constraints → verify joins

    The principal goals are:

    • Store each fact in an appropriate place
    • Reduce unnecessary repetition
    • Prevent contradictory values
    • Support reliable inserts, updates, and deletes
    • Clarify entity and relationship ownership
    • Improve maintainability
    • Preserve data integrity

    Data Redundancy

    Data redundancy occurs when the same fact is stored repeatedly in several rows or columns.

    Redundant Order Data

    Order Customer Email Product Product Name Quantity
    ORD-1001 CUS-42 customer@example.com PRD-10 Keyboard 1
    ORD-1001 CUS-42 customer@example.com PRD-20 Mouse 2
    ORD-1002 CUS-42 customer@example.com PRD-30 Monitor 1

    The customer email is repeated for every purchased product. Product names can also repeat across many orders.

    If one repeated value is updated and another is missed, the database can contain contradictory versions of the same fact.

    Modification Anomalies

    Poorly structured relations commonly produce three types of anomalies.

    Anomaly Meaning
    Insertion anomaly A fact cannot be stored without inserting an unrelated fact
    Update anomaly One fact must be updated in several places
    Deletion anomaly Deleting one fact unintentionally removes another fact

    Insertion Anomaly

    Problem:
    
    Product data exists only inside order rows.
    
    A new product cannot be stored
    until somebody places an order.

    Update Anomaly

    Problem:
    
    A customer's email occurs in 200 order rows.
    
    The email changes.
    
    All 200 rows must be updated.
    
    If one row is missed,
    two email values exist for one customer.

    Deletion Anomaly

    Problem:
    
    A product appears only in one order row.
    
    Deleting that order removes
    the only stored product information.

    Functional Dependencies

    A functional dependency exists when the value of one attribute or attribute set determines the value of another attribute.

    If attribute set \(X\) determines attribute set \(Y\), the dependency is written as:

    \[ X \rightarrow Y \]

    Customer Dependency

    customer_id -> display_name
    customer_id -> email_address
    customer_id -> customer_status

    For one customer ID, the model expects one corresponding display name, email address, and status at a given point in the modeled state.

    Order-line Dependency

    (order_id, line_number)
        ->
    product_id
    quantity
    unit_price

    The complete composite key determines the attributes of one order line.

    Determinants

    In the dependency \(X \rightarrow Y\), \(X\) is called the determinant.

    Dependency:
    
    product_id -> product_name
    
    
    Determinant:
    
    product_id
    
    
    Dependent attribute:
    
    product_name

    Understanding determinants helps identify which facts belong together in one relation.

    Normal Forms

    Normal forms are progressive relational-design conditions. Each level addresses particular dependency and redundancy problems.

    Normal Form Primary Concern
    First Normal Form Atomic values and no repeating groups
    Second Normal Form No partial dependency on part of a composite candidate key
    Third Normal Form No inappropriate transitive dependency through non-key attributes
    Boyce-Codd Normal Form Every determinant is a candidate key
    Fourth Normal Form No problematic independent multivalued dependencies
    Fifth Normal Form No problematic join dependencies requiring further lossless decomposition

    First Normal Form

    A relation in First Normal Form, abbreviated as 1NF, stores one value belonging to the declared domain in each row-and-column intersection and avoids repeating groups.

    First Normal Form Violation

    Customer ID Name Phone Numbers
    CUS-42 Example Customer 1111111111, 2222222222, 3333333333

    The telephone column contains a list rather than one value from its intended telephone-number domain.

    First Normal Form Design

    CREATE TABLE customers
    (
        customer_id BIGINT PRIMARY KEY,
        display_name VARCHAR(200) NOT NULL
    );
    
    CREATE TABLE customer_phone_numbers
    (
        phone_number_id BIGINT PRIMARY KEY,
        customer_id BIGINT NOT NULL,
        phone_number VARCHAR(30) NOT NULL,
        phone_type VARCHAR(20) NOT NULL,
    
        CONSTRAINT fk_customer_phone_customer
            FOREIGN KEY (customer_id)
            REFERENCES customers (customer_id),
    
        CONSTRAINT uq_customer_phone
            UNIQUE
            (
                customer_id,
                phone_number
            )
    );

    Each telephone number is represented by a separate row associated with the customer.

    Repeating Groups

    Repeating columns
    product_1 VARCHAR(100),
    quantity_1 INT,
    product_2 VARCHAR(100),
    quantity_2 INT,
    product_3 VARCHAR(100),
    quantity_3 INT

    This design imposes an arbitrary maximum number of products and requires structural changes when another item is added.

    Related rows
    CREATE TABLE order_lines
    (
        order_id BIGINT NOT NULL,
        line_number INT NOT NULL,
        product_id BIGINT NOT NULL,
        quantity INT NOT NULL,
    
        PRIMARY KEY
        (
            order_id,
            line_number
        )
    );

    Second Normal Form

    A relation is in Second Normal Form, abbreviated as 2NF, when it is in 1NF and every non-key attribute depends on the complete candidate key rather than only part of a composite key.

    Partial dependency is relevant when a candidate key contains more than one attribute.

    Relation with Partial Dependencies

    ORDER_PRODUCT
    
    Composite key:
    (order_id, product_id)
    
    Attributes:
    order_date
    customer_id
    product_name
    current_price
    quantity

    Dependencies include:

    order_id
        ->
    order_date
    customer_id
    
    
    product_id
        ->
    product_name
    current_price
    
    
    (order_id, product_id)
        ->
    quantity

    The order attributes depend only on order_id. Product attributes depend only on product_id. Only quantity depends on the entire composite key.

    Decomposition into Second Normal Form

    CREATE TABLE orders
    (
        order_id BIGINT PRIMARY KEY,
        customer_id BIGINT NOT NULL,
        order_date DATE NOT NULL
    );
    
    CREATE TABLE products
    (
        product_id BIGINT PRIMARY KEY,
        product_name VARCHAR(200) NOT NULL,
        current_price DECIMAL(18, 2) NOT NULL
    );
    
    CREATE TABLE order_lines
    (
        order_id BIGINT NOT NULL,
        product_id BIGINT NOT NULL,
        quantity INT NOT NULL,
    
        PRIMARY KEY
        (
            order_id,
            product_id
        ),
    
        FOREIGN KEY (order_id)
            REFERENCES orders (order_id),
    
        FOREIGN KEY (product_id)
            REFERENCES products (product_id)
    );

    Second Normal Form rule: When a table has a composite key, verify that every non-key attribute describes the complete key, not only one component of it.

    Third Normal Form

    A relation is in Third Normal Form, abbreviated as 3NF, when it satisfies 2NF and does not contain an inappropriate transitive dependency in which a non-key fact depends on another non-key fact.

    Transitive Dependency Example

    EMPLOYEE
    
    employee_id
    employee_name
    department_id
    department_name
    department_location

    Dependencies include:

    employee_id
        ->
    employee_name
    department_id
    
    
    department_id
        ->
    department_name
    department_location

    Department name and location describe the department, not the employee. They depend on the employee key indirectly through department_id.

    Third Normal Form Decomposition

    CREATE TABLE departments
    (
        department_id BIGINT PRIMARY KEY,
        department_name VARCHAR(200) NOT NULL,
        department_location VARCHAR(200) NOT NULL
    );
    
    CREATE TABLE employees
    (
        employee_id BIGINT PRIMARY KEY,
        employee_name VARCHAR(200) NOT NULL,
        department_id BIGINT NOT NULL,
    
        CONSTRAINT fk_employees_department
            FOREIGN KEY (department_id)
            REFERENCES departments (department_id)
    );

    Department facts are stored once in the department relation. Employees reference the appropriate department.

    The Key, the Whole Key, and Nothing but the Key

    A memorable informal summary of the early normal forms is:

    Every non-key fact should depend on:
    
    The key
    The whole key
    And nothing but the key
    Phrase Related Concern
    The key The row has an identifiable meaning
    The whole key No partial dependency on part of a composite key
    Nothing but the key No inappropriate dependency through a non-key attribute

    This phrase is a learning aid rather than a complete formal definition. Formal normalization requires identifying all candidate keys and functional dependencies.

    Boyce-Codd Normal Form

    Boyce-Codd Normal Form, abbreviated as BCNF, is a stricter condition under which every determinant in a nontrivial functional dependency is a candidate key.

    Example Scenario

    TEACHING_ASSIGNMENT
    
    student_id
    course_id
    instructor_id
    
    
    Business rules:
    
    A student can take a course.
    
    Each instructor teaches one course.
    
    A course can have several instructors.

    Possible dependencies include:

    (student_id, course_id)
        ->
    instructor_id
    
    
    instructor_id
        ->
    course_id

    The instructor determines the course, but the instructor alone is not necessarily a candidate key for the complete assignment relation. This kind of dependency can require further decomposition.

    Possible Decomposition

    CREATE TABLE instructor_courses
    (
        instructor_id BIGINT PRIMARY KEY,
        course_id BIGINT NOT NULL,
    
        FOREIGN KEY (course_id)
            REFERENCES courses (course_id)
    );
    
    CREATE TABLE student_instructors
    (
        student_id BIGINT NOT NULL,
        instructor_id BIGINT NOT NULL,
    
        PRIMARY KEY
        (
            student_id,
            instructor_id
        ),
    
        FOREIGN KEY (student_id)
            REFERENCES students (student_id),
    
        FOREIGN KEY (instructor_id)
            REFERENCES instructor_courses (instructor_id)
    );

    The exact decomposition depends on the complete business rules and candidate keys. Do not normalize from a simplified example without confirming the real dependencies.

    Fourth Normal Form

    Fourth Normal Form, abbreviated as 4NF, addresses independent multivalued dependencies stored in one relation.

    Independent Multi-valued Facts

    EMPLOYEE_SKILL_LANGUAGE
    
    employee_id
    skill
    language
    
    
    Employee 1 skills:
    
    SQL
    Python
    
    
    Employee 1 languages:
    
    English
    Bengali

    If skills and languages are independent, storing both in one relation produces all combinations:

    Employee 1, SQL, English
    Employee 1, SQL, Bengali
    Employee 1, Python, English
    Employee 1, Python, Bengali

    The combinations imply no meaningful relationship between one skill and one language.

    Fourth Normal Form Decomposition

    CREATE TABLE employee_skills
    (
        employee_id BIGINT NOT NULL,
        skill_id BIGINT NOT NULL,
    
        PRIMARY KEY
        (
            employee_id,
            skill_id
        )
    );
    
    CREATE TABLE employee_languages
    (
        employee_id BIGINT NOT NULL,
        language_code VARCHAR(20) NOT NULL,
    
        PRIMARY KEY
        (
            employee_id,
            language_code
        )
    );

    Fifth Normal Form

    Fifth Normal Form, abbreviated as 5NF, addresses complex join dependencies where a relation can be decomposed further into smaller relations and reconstructed through joins without introducing incorrect combinations.

    These scenarios are less common in ordinary transactional application design. They require careful analysis of the complete business rules.

    Conceptual example involving:
    
    Supplier
    Product
    Region
    
    
    Possible facts:
    
    Supplier can supply Product.
    Supplier operates in Region.
    Product is approved in Region.
    
    
    Question:
    
    Does the combination of these binary facts
    always imply a valid supplier-product-region fact?

    The answer depends on the domain. A decomposition is correct only when its joins preserve exactly the valid original facts.

    Lossless Decomposition

    A decomposition is lossless when joining the decomposed relations reconstructs the original valid information without losing rows or creating false combinations.

    Original relation
          |
          v
    Decompose into smaller relations
          |
          v
    Join smaller relations
          |
          v
    Recover exactly the original facts

    Decomposition rule: Splitting a table is useful only when the resulting relations can be joined correctly through preserved keys and dependencies.

    Dependency Preservation

    A decomposition preserves dependencies when important business dependencies can be enforced directly on the decomposed relations without requiring expensive joins for every validation.

    Desired outcome:
    
    - Decomposition is lossless.
    - Important dependencies remain enforceable.
    - Keys and constraints remain understandable.
    - Queries can reconstruct required business views.

    A theoretically more normalized decomposition can be less practical when critical constraints become difficult to enforce. The final design requires careful trade-off analysis.

    Running Example: Unnormalized Order Data

    ORDER_DATA
    
    order_id
    order_date
    customer_id
    customer_name
    customer_email
    customer_city
    product_ids
    product_names
    quantities
    unit_prices
    salesperson_id
    salesperson_name

    This structure contains several problems:

    • Product attributes contain lists
    • Customer data repeats across orders
    • Product data repeats across order lines
    • Salesperson data repeats across orders
    • Order-line facts are mixed with order-level facts
    • Customer facts are mixed with transaction facts

    Convert the Example to First Normal Form

    Create one row for every order line and use atomic values.

    ORDER_DATA_1NF
    
    order_id
    product_id
    order_date
    customer_id
    customer_name
    customer_email
    customer_city
    product_name
    quantity
    unit_price
    salesperson_id
    salesperson_name

    A possible composite key is (order_id, product_id) when one product appears at most once per order. If repeated products are allowed, an order-line number is required.

    The table now has atomic values, but customer, product, salesperson, and order facts still repeat.

    Convert the Example to Second Normal Form

    Remove facts that depend on only part of the composite order-line key.

    ORDERS
    
    order_id
    order_date
    customer_id
    customer_name
    customer_email
    customer_city
    salesperson_id
    salesperson_name
    
    
    PRODUCTS
    
    product_id
    product_name
    
    
    ORDER_LINES
    
    order_id
    product_id
    quantity
    unit_price

    Order-level attributes move to ORDERS. Product-level attributes move to PRODUCTS. Order-line facts remain in ORDER_LINES.

    Convert the Example to Third Normal Form

    Customer and salesperson details do not directly describe the order key. They describe customer and salesperson entities.

    CUSTOMERS
    
    customer_id
    customer_name
    customer_email
    customer_city
    
    
    SALESPEOPLE
    
    salesperson_id
    salesperson_name
    
    
    ORDERS
    
    order_id
    order_date
    customer_id
    salesperson_id
    
    
    PRODUCTS
    
    product_id
    product_name
    
    
    ORDER_LINES
    
    order_id
    line_number
    product_id
    quantity
    unit_price

    Normalized SQL Schema

    CREATE TABLE customers
    (
        customer_id BIGINT PRIMARY KEY,
        customer_name VARCHAR(200) NOT NULL,
        customer_email VARCHAR(254) NOT NULL,
        customer_city VARCHAR(100) NOT NULL,
    
        CONSTRAINT uq_customers_email
            UNIQUE (customer_email)
    );
    
    CREATE TABLE salespeople
    (
        salesperson_id BIGINT PRIMARY KEY,
        salesperson_name VARCHAR(200) NOT NULL
    );
    
    CREATE TABLE products
    (
        product_id BIGINT PRIMARY KEY,
        product_name VARCHAR(200) NOT NULL
    );
    
    CREATE TABLE orders
    (
        order_id BIGINT PRIMARY KEY,
        order_date DATE NOT NULL,
        customer_id BIGINT NOT NULL,
        salesperson_id BIGINT NOT NULL,
    
        CONSTRAINT fk_orders_customer
            FOREIGN KEY (customer_id)
            REFERENCES customers (customer_id),
    
        CONSTRAINT fk_orders_salesperson
            FOREIGN KEY (salesperson_id)
            REFERENCES salespeople (salesperson_id)
    );
    
    CREATE TABLE order_lines
    (
        order_id BIGINT NOT NULL,
        line_number INT NOT NULL,
        product_id BIGINT NOT NULL,
        quantity INT NOT NULL,
        unit_price DECIMAL(18, 2) NOT NULL,
    
        PRIMARY KEY
        (
            order_id,
            line_number
        ),
    
        CONSTRAINT fk_order_lines_order
            FOREIGN KEY (order_id)
            REFERENCES orders (order_id),
    
        CONSTRAINT fk_order_lines_product
            FOREIGN KEY (product_id)
            REFERENCES products (product_id),
    
        CONSTRAINT ck_order_lines_quantity
            CHECK (quantity > 0),
    
        CONSTRAINT ck_order_lines_price
            CHECK (unit_price >= 0)
    );

    Historical Snapshots Are Not Always Denormalization

    Repeating data is not automatically a normalization mistake. Sometimes two similar-looking values represent different facts.

    products.current_price:
    
    The product's current selling price.
    
    
    order_lines.unit_price:
    
    The price agreed when the order was placed.

    The values can differ legitimately because they describe different points in time and different business facts.

    Transaction Snapshot

    CREATE TABLE order_lines
    (
        order_id BIGINT NOT NULL,
        line_number INT NOT NULL,
        product_id BIGINT NOT NULL,
        product_description_snapshot VARCHAR(200) NOT NULL,
        quantity INT NOT NULL,
        unit_price_at_order DECIMAL(18, 2) NOT NULL,
    
        PRIMARY KEY
        (
            order_id,
            line_number
        )
    );

    Historical rule: A transaction-time snapshot is a separate fact when the business requires the historical record to remain unchanged after the current master data changes.

    What Is Denormalization?

    Denormalization deliberately stores selected duplicated, aggregated, or prejoined data to support a defined access pattern.

    Denormalization can reduce joins or repeated calculations for high-volume reads, but it introduces additional write and consistency responsibilities.

    Safe Denormalization Process
    measure workload → find verified bottleneck → select duplicate fact → define source of truth → define synchronization → monitor drift

    Normalization vs Denormalization

    Area Normalization Denormalization
    Primary goal Integrity and reduction of unnecessary redundancy Performance or read-path simplification
    Data repetition Minimized where facts have one source Introduced deliberately
    Read queries Can require joins Can avoid selected joins or calculations
    Writes Update the authoritative fact Can require updating several representations
    Consistency Usually easier to preserve Requires synchronization and reconciliation
    Storage Less repeated data Additional storage for copies or summaries
    Recommended starting point Default transactional design Measured and justified optimization

    When to Consider Denormalization

    Denormalization can be considered when:

    • A measured critical read query remains expensive after appropriate indexing
    • A frequently requested view requires many repeated joins
    • An aggregate is calculated continuously from a large dataset
    • A reporting workload needs a read-optimized model
    • A distributed read path cannot synchronously join data across services
    • A historical snapshot must remain stable
    • A precomputed projection improves a defined user workflow

    Denormalization should not be the first response to a slow query. First inspect the query plan, indexes, selected columns, filters, pagination, and database configuration.

    When Not to Denormalize

    Avoid denormalization when:

    • No performance bottleneck has been measured
    • The duplicated values change frequently
    • No synchronization owner exists
    • Strong immediate consistency is mandatory
    • The normalized query can be fixed with an appropriate index
    • The team cannot monitor and repair data drift
    • The additional write complexity exceeds the read benefit

    Precomputed Aggregate

    An order total can be calculated from its lines whenever the order is retrieved.

    SELECT
        order_id,
        SUM(quantity * unit_price)
            AS calculated_total
    FROM order_lines
    WHERE
        order_id = :order_id
    GROUP BY
        order_id;

    A denormalized design can store the total on the order row:

    ALTER TABLE orders
    ADD COLUMN total_amount DECIMAL(18, 2) NOT NULL;

    The stored total must be updated whenever a price, quantity, discount, tax, fee, or line membership changes.

    Transactional Maintenance

    Begin transaction
    
    1. Insert or update order line.
    2. Recalculate order total.
    3. Update orders.total_amount.
    4. Validate order invariants.
    
    Commit transaction

    Duplicated Display Value

    A frequently displayed customer name can be copied into an order read model to avoid a repeated join.

    CREATE TABLE order_read_model
    (
        order_id BIGINT PRIMARY KEY,
        order_number VARCHAR(30) NOT NULL,
        customer_id BIGINT NOT NULL,
        customer_display_name VARCHAR(200) NOT NULL,
        order_status VARCHAR(30) NOT NULL,
        total_amount DECIMAL(18, 2) NOT NULL,
        ordered_at TIMESTAMP NOT NULL
    );

    The design must answer:

    • Is the copied name a historical snapshot or a current projection?
    • Which table is authoritative?
    • When is the copy updated?
    • What temporary staleness is acceptable?
    • How is drift detected and repaired?

    Materialized Read Models

    A read model stores data shaped for a specific query or screen.

    Normalized write model:
    
    Customers
    Orders
    Order Lines
    Payments
    Shipments
    
    
    Read model:
    
    Order Summary
    
    - Order ID
    - Customer display name
    - Current order status
    - Payment status
    - Shipment status
    - Total amount

    The normalized model remains the authoritative transactional store. The read model is rebuilt or updated from authoritative changes.

    Materialized Views

    Some database systems support materialized views that store query results physically and refresh them according to a defined policy.

    CREATE MATERIALIZED VIEW customer_order_summary AS
    SELECT
        c.customer_id,
        c.customer_name,
        COUNT(o.order_id) AS order_count,
        SUM(o.total_amount) AS lifetime_order_value
    FROM customers AS c
    LEFT JOIN orders AS o
        ON o.customer_id = c.customer_id
    GROUP BY
        c.customer_id,
        c.customer_name;

    Syntax and refresh capabilities differ between database platforms. The refresh frequency determines how current the stored results are.

    Synchronization Strategies

    Strategy Behaviour Consideration
    Same database transaction Updates normalized and denormalized values atomically Works when both are inside one transaction boundary
    Database trigger Updates derived data after database changes Logic can become hidden from application code
    Background job Refreshes copies periodically Introduces bounded staleness
    Event-driven projection Updates read models from published changes Requires reliable event processing and replay
    Scheduled rebuild Recreates the derived model from source data Can consume significant resources

    Eventual Consistency

    An asynchronously updated read model can temporarily differ from the authoritative normalized data.

    Authoritative customer name changes
            |
            v
    Transaction commits
            |
            v
    Change event is published
            |
            v
    Projection consumer processes event
            |
            v
    Order read model is updated

    Between the source commit and projection update, readers can observe the old value.

    The contract should define:

    • Which source is authoritative
    • Expected staleness
    • Update ordering
    • Retry behaviour
    • Duplicate-event handling
    • Rebuild and reconciliation procedures

    Detecting Data Drift

    Data drift occurs when a denormalized representation no longer agrees with its authoritative source.

    SELECT
        orm.order_id,
        orm.customer_display_name
            AS copied_name,
        c.customer_name
            AS authoritative_name
    FROM order_read_model AS orm
    INNER JOIN orders AS o
        ON o.order_id = orm.order_id
    INNER JOIN customers AS c
        ON c.customer_id = o.customer_id
    WHERE
        orm.customer_display_name
            <> c.customer_name;

    A reconciliation job can measure differences and repair them according to the read model's synchronization policy.

    Read and Write Amplification

    Concept Meaning
    Read amplification One logical read requires several lookups, joins, or service calls
    Write amplification One logical change requires several stored representations to be updated

    Normalized designs can increase read joins. Denormalized designs can increase write amplification. The correct design depends on workload, consistency, maintainability, and failure requirements.

    Transactional vs Analytical Models

    Workload Typical Characteristics Common Modeling Direction
    Transactional Frequent inserts and updates, point lookups, strong integrity Normalized operational model
    Analytical Large scans, aggregations, historical reporting Read-optimized dimensional or denormalized model
    Operational reporting Current summaries across several entities Indexed query, materialized view, or projection

    One application can use a normalized transactional model and a separate denormalized analytical model rather than forcing one schema to optimize every workload.

    Star-schema Example

    Analytical systems commonly organize measurable events in a fact table and descriptive information in dimension tables.

    FACT_SALES
       |
       +-- DATE_DIMENSION
       |
       +-- CUSTOMER_DIMENSION
       |
       +-- PRODUCT_DIMENSION
       |
       +-- STORE_DIMENSION

    Dimension tables can intentionally contain descriptive attributes optimized for analytical queries. This is a different workload and design objective from normalized transactional processing.

    Join Cost Is Not Automatically a Problem

    A normalized query containing joins is not necessarily slow. Relational databases are designed to join tables using indexes and optimized execution plans.

    SELECT
        o.order_number,
        c.customer_name,
        o.order_status,
        o.total_amount
    FROM orders AS o
    INNER JOIN customers AS c
        ON c.customer_id = o.customer_id
    WHERE
        o.order_id = :order_id;

    Before denormalizing, verify:

    • The foreign-key columns are indexed appropriately
    • The query predicates are selective
    • The query retrieves only required columns
    • The execution plan uses appropriate access paths
    • Statistics are current
    • The request is paginated where applicable
    • The actual latency is a user-facing bottleneck

    Integrity after Denormalization

    Every denormalized value needs a documented integrity contract.

    Question Required Decision
    What is authoritative? Identify the source of truth
    Who updates the copy? Assign one synchronization owner
    When is it updated? Define synchronous or asynchronous propagation
    How stale may it be? Define an acceptable consistency window
    How are failures retried? Define durable and idempotent processing
    How is drift detected? Implement reconciliation and metrics
    How is it rebuilt? Maintain a repeatable rebuild procedure

    Security and Denormalized Data

    Duplicating data expands the number of locations that require access control, encryption, retention, auditing, and deletion handling.

    Review whether denormalization duplicates:

    • Personal information
    • Payment information
    • Authentication or authorization data
    • Confidential business data
    • Tenant identifiers
    • Deletion-controlled information

    Data-minimization rule: Do not copy sensitive data into a read model merely because it is convenient. Include only the fields required for the documented use case.

    Observability

    Useful normalization and denormalization metrics include:

    • Duplicate-value conflict count
    • Foreign-key violation count
    • Read-model update delay
    • Projection processing failures
    • Source-to-copy drift count
    • Materialized-view refresh duration
    • Normalized query latency
    • Denormalized query latency
    • Write amplification
    • Reconciliation repair count
    • Read-model rebuild duration
    • Storage consumed by duplicated data

    Normalization Workflow

    1. Identify the relation's intended meaning.
    2. Identify candidate keys.
    3. List functional and multivalued dependencies.
    4. Identify repeating groups and non-atomic attributes.
    5. Move independent repeated values into related rows.
    6. Identify partial dependencies on composite-key components.
    7. Move partial dependencies into their own relations.
    8. Identify transitive dependencies through non-key attributes.
    9. Move separate entity facts into their own relations.
    10. Verify lossless decomposition.
    11. Verify dependency preservation.
    12. Add primary, foreign, unique, and check constraints.
    13. Test realistic inserts, updates, deletes, and joins.

    Denormalization Workflow

    1. Begin with a correct normalized model.
    2. Measure the production or representative workload.
    3. Identify one verified read bottleneck.
    4. Inspect indexes, query plans, filters, and pagination first.
    5. Define the exact duplicated or precomputed value.
    6. Identify the authoritative source.
    7. Choose a synchronization mechanism.
    8. Define acceptable staleness.
    9. Add reconciliation and rebuild procedures.
    10. Protect duplicated sensitive data.
    11. Load-test read and write paths.
    12. Document the reason and ownership.

    Common Normalization and Denormalization Mistakes

    1

    Storing Lists in One Column

    Comma-separated or encoded lists are difficult to validate, join, constrain, and index relationally.

    2

    Confusing Atomic with Physically Indivisible

    Atomicity depends on the modeled domain and required operations. An address can be one value in one model and several attributes in another.

    3

    Ignoring Candidate Keys

    Normalization must consider all relevant candidate keys, not only the selected primary key.

    4

    Leaving Partial Dependencies in Junction Tables

    Attributes describing only one side of a composite key belong with that entity.

    5

    Leaving Transitive Dependencies in Entity Tables

    Department, region, category, or supplier facts should not be repeated in every related entity row.

    6

    Splitting Tables without Lossless Joins

    An incorrect decomposition can lose original facts or create false combinations when the tables are joined.

    7

    Over-normalizing without Workload Awareness

    Excessive fragmentation can make important constraints and access paths unnecessarily complex.

    8

    Denormalizing before Measuring

    Additional copies and synchronization logic should not be introduced without evidence that they solve a significant problem.

    9

    Using Denormalization instead of Indexing

    A slow normalized query might need an appropriate index or improved query rather than duplicated data.

    10

    Not Defining the Source of Truth

    Two editable copies of one fact can diverge when neither is declared authoritative.

    11

    Ignoring Projection Failures

    Asynchronous read models require retries, idempotency, monitoring, replay, and reconciliation.

    12

    Calling Historical Snapshots Redundancy Errors

    A current product price and the price recorded on an earlier order are separate business facts.

    Recommended Test Cases

    Test Expected Evidence
    Atomic values One relational value is stored in each attribute position
    Repeating groups Repeated items are represented as related rows
    Partial dependency Every non-key order-line fact depends on the complete line key
    Transitive dependency Department facts are stored separately from employee facts
    Lossless join Joining decomposed tables reconstructs valid original facts
    Insertion anomaly A product can be stored before it appears in an order
    Update anomaly A customer email is changed in one authoritative location
    Deletion anomaly Deleting an order does not remove the customer or product
    Historical snapshot Existing order prices remain unchanged after the current product price changes
    Denormalized update The copied value follows the documented synchronization policy
    Projection failure The update is retried or repaired without silent data loss
    Reconciliation Drift between authoritative and copied values is detected

    Best Practices

    Recommended Practices

    • Begin with entities, relationships, candidate keys, and business dependencies.
    • Keep one authoritative location for each current fact.
    • Use related rows instead of lists or repeating columns.
    • Remove partial dependencies from composite-key relations.
    • Remove inappropriate transitive dependencies.
    • Verify all candidate keys, not only the primary key.
    • Require lossless decomposition.
    • Preserve important dependencies where practical.
    • Implement keys, foreign keys, unique constraints, and checks.
    • Distinguish current master data from historical transaction snapshots.
    • Use normalization as the default for transactional models.
    • Measure query performance before denormalizing.
    • Optimize indexes, queries, and pagination before adding copies.
    • Define one authoritative source for every duplicated value.
    • Document synchronization and acceptable staleness.
    • Make asynchronous projection updates idempotent and replayable.
    • Implement drift detection and reconciliation.
    • Protect every duplicated copy of sensitive information.
    • Document the reason and owner for each denormalization.
    • Retest integrity and performance after schema changes.

    Practice Exercise

    Normalize an online learning-platform enrollment table and design one justified denormalized read model.

    Starting Relation

    COURSE_ACTIVITY
    
    learner_id
    learner_name
    learner_email
    course_id
    course_title
    category_id
    category_name
    instructor_ids
    instructor_names
    chapter_id
    chapter_title
    lesson_id
    lesson_title
    enrollment_date
    completion_percentage
    latest_quiz_score

    Requirements

    1. Identify candidate keys and functional dependencies.
    2. Remove repeating instructor values.
    3. Create separate learner, course, category, instructor, chapter, and lesson entities.
    4. Create an enrollment associative entity.
    5. Create a course-instructor junction table.
    6. Define chapter-to-course and lesson-to-chapter relationships.
    7. Create a quiz-attempt table that preserves attempt history.
    8. Verify First, Second, and Third Normal Forms.
    9. Define primary, foreign, unique, and check constraints.
    10. Write a query returning learner course progress.
    11. Measure the query using representative data.
    12. Create a course-progress read model only if justified.
    13. Define the normalized source of truth.
    14. Define projection synchronization and acceptable staleness.
    15. Create a reconciliation query for the read model.

    Suggested Normalized Tables

    Table Purpose Primary Relationship
    Learners Stores learner facts One learner has many enrollments
    Categories Stores course-category facts One category has many courses
    Courses Stores course facts One course has many chapters and enrollments
    Instructors Stores instructor facts Many instructors can teach many courses
    Course Instructors Associates courses and instructors Many-to-many junction
    Chapters Stores chapter facts Each chapter belongs to one course
    Lessons Stores lesson facts Each lesson belongs to one chapter
    Enrollments Stores learner-course relationship facts Many-to-many associative entity
    Quiz Attempts Stores immutable attempt history One learner can make several attempts

    Frequently Asked Questions

    1

    What is database normalization?

    Normalization is the process of organizing relational data to reduce unnecessary redundancy and prevent modification anomalies.

    2

    What is First Normal Form?

    First Normal Form requires relational values without repeating groups, such as several telephone numbers stored in one field.

    3

    What is Second Normal Form?

    Second Normal Form requires 1NF and removes dependencies in which a non-key attribute depends on only part of a composite candidate key.

    4

    What is Third Normal Form?

    Third Normal Form requires 2NF and removes inappropriate transitive dependencies through non-key attributes.

    5

    What is Boyce-Codd Normal Form?

    Boyce-Codd Normal Form requires every determinant in a nontrivial functional dependency to be a candidate key.

    6

    What is an update anomaly?

    An update anomaly occurs when one fact exists in several locations and must be updated consistently in all of them.

    7

    What is lossless decomposition?

    A decomposition is lossless when joining the resulting relations reconstructs exactly the valid original facts.

    8

    What is denormalization?

    Denormalization deliberately stores duplicated, aggregated, or prejoined data to optimize a defined access pattern.

    9

    Does normalization always improve performance?

    Normalization primarily improves integrity and maintainability. Read performance depends on queries, indexes, data volume, execution plans, and workload.

    10

    Should every database be fully normalized?

    Transactional schemas commonly target a well-normalized design, but the appropriate final form depends on dependencies, constraints, workloads, and maintainability requirements.

    11

    Is a historical snapshot denormalization?

    Not necessarily. A transaction-time value can represent a distinct historical fact rather than an unnecessary copy of current master data.

    12

    What comes after normalization and denormalization?

    The next topic is keys and constraints, followed by ACID and transactions.

    Key Takeaway

    Normalization organizes relational facts according to keys and dependencies. First Normal Form removes repeating groups, Second Normal Form removes partial dependencies, Third Normal Form removes inappropriate transitive dependencies, and BCNF requires every determinant to be a candidate key. Decomposition should be lossless and preserve important dependencies. Denormalization is a deliberate read optimization, not a shortcut for poor modeling. Introduce it only after measurement, identify one authoritative source, define synchronization and acceptable staleness, detect drift, protect duplicated sensitive data, and retain a reliable normalized model from which projections can be repaired or rebuilt.