ABOUT PORTFOLIO BLOG GALLERY RESOURCES CONTACT
Home / Blog / Software Engineering

What Is Database Normalization? A Simple Explanation

Author

Rizal Azis

Author

Sep 06, 2026
16 Min Read
What Is Database Normalization? A Simple Explanation

Learn what database normalization is, why it matters, the first three normal forms explained simply, and how normalization can improve database design.

If you've ever worked with a database, you've probably seen tables that look something like this:

Order ID

Customer Name

Customer Email

Product

Price

1001

John

john@email.com

Laptop

1200

1002

John

john@email.com

Mouse

25

1003

Sarah

sarah@email.com

Keyboard

80

At first glance, this looks perfectly fine.

The application can read it.

The SQL query works.

And everyone is happy.

Until the database gets bigger.

Then you start seeing duplicate data, inconsistent information, difficult updates, and increasingly complicated queries.

This is where database normalization becomes useful.

The word normalization sounds more complicated than it actually is.

At its core, database normalization is about organizing data so that it is easier to maintain, less repetitive, and less likely to become inconsistent.

In this article, we'll explain database normalization in simple terms, look at the most common normal forms, and understand when normalization is useful in real-world applications.

What Is Database Normalization?

Database normalization is a database design technique used to organize data into related tables in order to reduce unnecessary duplication and improve data consistency.

Instead of storing everything in one giant table, we separate different types of information into logical tables.

For example, instead of:

Orders
---------------------------------------------
Order ID | Customer | Email | Product | Price

we might create:

Customers
---------------------------
Customer ID | Name | Email

Products
---------------------------
Product ID | Name | Price

Orders
---------------------------
Order ID | Customer ID

Order Items
---------------------------
Order ID | Product ID | Quantity

Now each table has a clearer responsibility.

Customers stores customer information.

Products stores product information.

Orders stores order information.

Order Items connects orders with products.

That's the basic idea.

Why Do We Need Database Normalization?

The main reason is data duplication.

Let's say John places 100 orders.

In an unnormalized database, his name and email might be stored 100 times.

Order 1 → John → john@email.com
Order 2 → John → john@email.com
Order 3 → John → john@email.com
...
Order 100 → John → john@email.com

This creates unnecessary repetition.

But duplication isn't just a storage problem.

It can also create data inconsistency.

Imagine John changes his email address.

You need to update it in 100 rows.

What if you update 99 and accidentally miss one?

Now your database contains two versions of John's email.

That's a much bigger problem.

Normalization helps avoid situations like this by storing each piece of information in the appropriate place.

The Real Problem: Data Anomalies

Database normalization is largely about preventing something called data anomalies.

There are three common types.

Update Anomaly

The same information exists in multiple places.

You update one record but forget another.

Now the database contains inconsistent data.

Insert Anomaly

You cannot add information without also adding unrelated information.

For example, you want to create a new product, but your table requires an order to exist first.

That design creates an unnecessary dependency.

Delete Anomaly

Deleting one piece of information accidentally removes something else you still needed.

For example, deleting the last order for a customer might accidentally remove the only record containing that customer's information.

Good database design tries to prevent these problems.

A Simple Example of a Badly Designed Table

Imagine this table:

Student ID

Student Name

Course 1

Course 2

Course 3

1

John

Math

Physics

History

2

Sarah

Biology

Math

NULL

Looks simple.

But what happens if a student takes 10 courses?

Do we add:

Course 4
Course 5
Course 6
...

That's a warning sign.

The table structure is trying to store multiple values in columns instead of modeling the relationship properly.

A better design might be:

Students

Student ID

Name

1

John

2

Sarah

Courses

Course ID

Course Name

101

Math

102

Physics

103

History

104

Biology

Enrollments

Student ID

Course ID

1

101

1

102

1

103

2

104

2

101

Now the database can handle as many courses as necessary without changing the table structure.

This is one of the main ideas behind normalization.


The First Three Normal Forms

There are several normal forms in relational database design.

You don't necessarily need to memorize all of them to design practical applications.

The first three are the most commonly discussed:

  • First Normal Form (1NF)

  • Second Normal Form (2NF)

  • Third Normal Form (3NF)

Let's look at them without making things unnecessarily complicated.

First Normal Form (1NF)

The basic idea of 1NF is:

Each column should contain atomic, indivisible values, and each row should represent a distinct record.

In simpler terms:

Don't put multiple values inside one field.

For example, this isn't ideal:

Customer ID

Name

Phone Numbers

1

John

12345, 67890

The Phone Numbers column contains multiple values.

A more normalized design could be:

Customers

Customer ID

Name

1

John

Customer Phones

Customer ID

Phone

1

12345

1

67890

Now each field contains one value.

This is much easier to query and maintain.

Second Normal Form (2NF)

The concept of 2NF builds on 1NF.

The table should:

  1. Already satisfy 1NF.

  2. Ensure that non-key attributes depend on the whole primary key, not just part of it.

This becomes especially important when a table has a composite primary key.

Consider:

Order ID

Product ID

Product Name

Quantity

1001

101

Laptop

1

1001

102

Mouse

2

1002

101

Laptop

1

Suppose the primary key is:

(Order ID, Product ID)

Quantity depends on both Order ID and Product ID.

But Product Name depends only on Product ID.

That's a partial dependency.

Instead of storing Product Name here, we can move it to the Products table.

Products

Product ID

Product Name

101

Laptop

102

Mouse

Order Items

Order ID

Product ID

Quantity

1001

101

1

1001

102

2

1002

101

1

Now the data has a clearer structure.

Third Normal Form (3NF)

3NF goes one step further.

The basic idea is:

Non-key attributes should depend on the key, the whole key, and nothing but the key.

That's the classic phrase.

Here's a simpler way to understand it:

A column should describe the thing identified by the primary key—not another unrelated thing.

Consider:

Employee ID

Employee Name

Department ID

Department Name

1

John

10

Engineering

2

Sarah

10

Engineering

3

David

20

Marketing

Department Name doesn't really describe the employee.

It describes the department.

So we can separate it.

Employees

Employee ID

Employee Name

Department ID

1

John

10

2

Sarah

10

3

David

20

Departments

Department ID

Department Name

10

Engineering

20

Marketing

Now each table represents one clear subject.


Database Normalization vs Denormalization

Here's where things get interesting.

If normalization is so useful, should we normalize everything?

Not necessarily.

Sometimes databases are intentionally denormalized.

Denormalization means adding some controlled duplication or combining data to improve read performance or simplify certain queries.

For example, imagine a reporting system that needs to display:

Customer
Order
Product
Total

If generating this report requires joining ten tables every time, the query could become expensive depending on the workload and database design.

A team might decide to store some precomputed or duplicated data to make reads faster.

That's denormalization.

So the real goal isn't:

“Normalize everything.”

It's:

“Choose a database structure that fits the application's needs.”

When Should You Normalize Your Database?

Normalization is especially useful when:

Data Changes Frequently

If customer information changes often, keeping customer data in one place reduces the chance of inconsistent copies.

Data Has Clear Relationships

Examples:

Customer → Orders
Order → Products
Employee → Department
Student → Courses

These relationships are good candidates for separate tables.

You Need Strong Data Integrity

When the same information is stored in multiple places, maintaining consistency becomes harder.

Normalization can help establish clearer ownership of data.

Your Application Is Transactional

Systems such as:

  • E-commerce

  • Banking

  • ERP

  • CRM

  • Inventory management

  • HR systems

often benefit from carefully normalized relational models.

The exact design still depends on the workload and business requirements.

When Should You Consider Denormalization?

Denormalization can make sense when:

Read Performance Matters More

If the application reads data much more often than it writes, some duplication may be acceptable.

Queries Are Extremely Complex

Repeated joins across many large tables can become expensive in some workloads.

You're Building Analytics or Reporting Systems

Analytical workloads often use different modeling strategies from transactional systems.

For example, data warehouses frequently favor models designed for efficient analytical queries rather than strict transactional normalization.

You Have Measured a Real Performance Problem

This is important.

Don't denormalize because:

“Joins are bad.”

Joins are a normal part of relational databases.

Denormalize when there is a measured reason to do so.

Performance decisions should come from actual workload data, not assumptions.

Does Normalization Make Queries Faster?

This is a common misunderstanding.

Not automatically.

Normalization can improve data quality and reduce redundancy, but it can also introduce additional joins.

For example:

SELECT *
FROM orders
JOIN customers ON orders.customer_id = customers.id
JOIN order_items ON orders.id = order_items.order_id
JOIN products ON order_items.product_id = products.id;

This query involves multiple tables.

For transactional applications, that is often perfectly reasonable.

But if your workload requires extremely fast analytical queries over huge datasets, a different design might perform better.

Again, there is no universal answer.

Normalization Is About Data Structure, Not Just Performance

This is one of the most important lessons.

Developers sometimes think:

“Normalization = performance optimization.”

That's not really the primary goal.

Normalization is mainly about:

Reducing redundancy.

Improving consistency.

Clarifying relationships.

Avoiding anomalies.

Performance is a separate concern.

Sometimes normalization helps performance.

Sometimes it creates more joins.

Sometimes denormalization is the better choice.

That's why database design should start with understanding the problem.

A Practical Example: E-Commerce Database

Let's build a simple e-commerce example.

Instead of storing:

Order ID

Customer Name

Customer Email

Product

Product Price

Quantity

1001

John

john@email.com

Laptop

1200

1

1001

John

john@email.com

Mouse

25

2

We could use:

Customers

id
name
email

Products

id
name
price

Orders

id
customer_id
created_at
status

Order Items

id
order_id
product_id
quantity
price

Notice something interesting.

You may still keep price inside order_items.

Why?

Because the current product price can change later.

Imagine a customer buys a laptop for $1,200.

Six months later, the price becomes $900.

If you only store the current price in products, your historical order could incorrectly show $900.

So storing the purchase price in order_items can be intentional.

This is a great example of why database design isn't about blindly following normalization rules.

You also need to understand the business meaning of the data.

Normalization and Foreign Keys

Normalization often works together with primary keys and foreign keys.

For example:

CREATE TABLE customers (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(255)
);

Then:

CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    customer_id BIGINT,
    created_at TIMESTAMP,
    FOREIGN KEY (customer_id)
        REFERENCES customers(id)
);

Here:

customers.id

is the primary key.

And:

orders.customer_id

references it as a foreign key.

This relationship allows the database to represent:

One customer → Many orders

It also helps protect referential integrity.

Common Database Normalization Mistakes

1. One Giant Table

Putting customer, product, order, payment, and shipping information into one table may seem convenient.

It usually creates duplication and makes the data harder to maintain.

2. Repeating Columns

Columns like:

phone1
phone2
phone3

or:

product1
product2
product3

are often signs that the data model needs another table.

3. Duplicating Data Without a Reason

Sometimes duplication is intentional.

But if the same business fact exists in five different places and nobody knows which one is the source of truth, that's a problem.

4. Normalizing Too Aggressively

You can also go too far.

If every tiny value gets its own table, the schema can become unnecessarily complicated.

Good database design is about balance.

5. Ignoring the Business Domain

A technically “correct” normalized design can still be wrong for the business.

You need to understand what the data actually represents.

How to Think About Normalization

Instead of memorizing every normal form, start with these questions:

What does this table represent?

A table should have a clear purpose.

What does each column describe?

Each column should belong logically to the entity represented by the row.

Is the same information stored multiple times?

If yes, ask why.

Can this data change independently?

If it can, it may deserve its own table.

What are the relationships?

Think in terms of:

One-to-One
One-to-Many
Many-to-Many

What is the source of truth?

When data changes, you should know which table owns that information.

These questions are often more useful than simply memorizing “1NF, 2NF, 3NF.”

A Simple Mental Model

Here's an easy way to think about database normalization.

Imagine your desk.

Without organization:

Documents
Receipts
Passwords
Phone numbers
Invoices
Notes
Photos

Everything is mixed together.

You can still find things.

But eventually it becomes difficult.

Now organize everything:

Documents
Receipts
Invoices
Notes
Contacts
Photos

Each category has a clear purpose.

That's essentially what normalization tries to achieve in a database.

Put related information together, separate unrelated information, and reduce unnecessary duplication.

Final Thoughts

Database normalization may sound like an advanced database concept, but the core idea is actually simple:

Don't store the same business information everywhere unless you have a good reason to do so.

Instead, organize data into logical tables and connect those tables through relationships.

The first three normal forms—1NF, 2NF, and 3NF—give developers a useful framework for doing that.

But don't treat normalization as a rigid rulebook.

Real-world database design involves trade-offs.

Sometimes you need normalization for consistency.

Sometimes you need controlled denormalization for performance or reporting.

The important thing is to understand why you're making the decision.

A good database isn't the one with the most tables.

And it isn't the one with the fewest tables.

It's the one that represents the business data clearly, maintains data integrity, and works well for the application's actual workload.


Related Articles

What Is Software Architecture? A Beginner's Guide (2026)

Software Engineering — 14 min read

Monolithic vs Microservices: Which Architecture Should You Choose in 2026?

Software Engineering — 15 min read

Clean Architecture Explained with Real Project Example

Software Engineering — 12 min read