Skip to main content

Command Palette

Search for a command to run...

The Schema Decision That Cost Us Performance (And Could’ve Cost Us Money)

A practical deep dive into MySQL data types, covering INT, DECIMAL, CHAR, VARCHAR, DATETIME, and TIMESTAMP with real-world production insights.

Updated
8 min read
The Schema Decision That Cost Us Performance (And Could’ve Cost Us Money)
R

I am a full-stack developer (currently working with cognizant) who is passionate about web development and creating digital products with innovative solutions.

I hold 6+ years of experience in development, understanding clients' unique needs, and delivering quality code. I've honed my coding skills over these years through both my professional exposure and self-study. Have worked with teams that have used agile development methodology.

I am someone who likes to keep acquiring new skills and capabilities. And when I am not a web developer, I enjoy reading, writing and running.

My interests include:

  • Exploring new ideas
  • Learning about future tech & products
  • Finding user-friendly solutions to tech-related problems
  • Sharing my knowledge with close acquaintances

We didn’t notice it at first.

Queries were “a little slow.”
Disk usage was “a bit high.”
Reports were “slightly off by a few cents.”

Nothing dramatic.

But when we scaled, everything magnified.

Indexes grew huge.
Backups took longer.
And a rounding issue in financial calculations almost made it to production billing.

The root cause?

Not bad logic.
Not bad architecture.

Bad data types.

That’s when I learned something most tutorials barely emphasize:

Data types are not syntax.
They are performance, cost, and reliability decisions.

In this guide, we are going to explore 4 key concepts to help you master MySQL data types in production systems:

  1. Numeric types (INT, TINYINT, BIGINT)

  2. DECIMAL vs FLOAT vs DOUBLE

  3. CHAR vs VARCHAR

  4. DATE, DATETIME, and TIMESTAMP

This isn’t about memorizing ranges.

This is about designing schemas that don’t break at scale.


1️⃣ Data Types: The Containers of Your System

At a surface level, data types define how MySQL stores data internally.

But in production, they determine:

  • Storage size

  • Performance

  • Accuracy

  • Index efficiency

The Container Analogy

Think of data types like container sizes.

If you store a teaspoon of salt in a 10-liter bucket, you waste space.

If you try to store 10 liters in a teaspoon, it overflows.

The right container = efficient system.

The wrong container = slow queries, wasted memory, and scaling pain.


🔢 Numeric Types — INT, TINYINT, BIGINT

What They Are

Whole number types.

Type Range (Signed) Storage
TINYINT -128 to 127 1 byte
INT ~2 billion 4 bytes
BIGINT Very large 8 bytes

They look interchangeable.

They are not.


Real-World Scenario: Inventory System

You’re building an inventory system.

You need:

  • Product ID → INT

  • Stock quantity → INT

  • is_active flag → TINYINT

CREATE TABLE inventory (
  id INT AUTO_INCREMENT PRIMARY KEY,
  product_name VARCHAR(100),
  quantity INT,
  is_active TINYINT
);

Seems simple.

But here’s where things go wrong.


What Happens If You Use BIGINT Everywhere?

I’ve seen this a lot.

“Let’s just use BIGINT. Just in case.”

Sounds safe.

But:

  • BIGINT uses double the storage of INT.

  • Indexes become larger.

  • Memory usage increases.

  • Cache efficiency drops.

At scale, this matters.

If you have 50 million rows, doubling index size isn’t theoretical. It’s measurable.


Senior Dev Perspective

Use BIGINT when:

  • You expect distributed ID generation.

  • You’re designing for massive scale.

  • You genuinely risk INT overflow.

Otherwise?

Be intentional.

Small types → smaller indexes → faster joins.

And faster joins are everything.


💰 DECIMAL vs FLOAT vs DOUBLE — Where Money Gets Dangerous

This is where production mistakes become legal mistakes.


DECIMAL — Exact Precision

price DECIMAL(8,2)

8 total digits.
2 digits after decimal.

DECIMAL stores exact values.

No approximation.

Perfect for:

  • E-commerce pricing

  • Banking systems

  • Financial reporting


FLOAT and DOUBLE — Approximate Values

Type Precision
FLOAT ~7 digits
DOUBLE ~15 digits

These are stored in binary floating-point format.

That means:

0.1 + 0.2 ≠ exactly 0.3

In code, this feels minor.

In finance, this is catastrophic.


What Happens If You Use FLOAT for Money?

You get rounding inconsistencies.

Now imagine:

  • Monthly invoices slightly off.

  • Aggregated totals misaligned.

  • Regulatory audits questioning discrepancies.

Congratulations. You’ve built a lawsuit generator.


When FLOAT/DOUBLE Are Correct

They’re perfect for:

  • Scientific calculations

  • Sensor readings

  • Analytics

  • Large statistical datasets

Where tiny rounding errors are acceptable.


Senior Dev Perspective

Rule of thumb:

  • Money → DECIMAL

  • Science → DOUBLE

  • Never guess

Precision errors don’t crash loudly.

They accumulate silently.


🔤 CHAR vs VARCHAR — The Hidden Memory Trap

This looks small.

It isn’t.


VARCHAR — Flexible & Efficient

  • Variable length

  • Stores actual size

  • Recommended for most text fields

name VARCHAR(100)

If the name is 5 characters, it stores 5 characters.

Efficient.


CHAR — Fixed Length

  • Always consumes full space

  • Faster for fixed-size data

Example:

country_code CHAR(2)

Perfect for:

  • Country codes (IN, US)

  • State abbreviations

  • Fixed-length hashes


What Happens If You Misuse CHAR?

Let’s say:

You store usernames in CHAR(100).

Every record consumes full 100 characters.

Multiply that by millions of rows.

Your disk usage explodes.

Backups grow.
Replication slows.
I/O increases.

All because of a schema decision.


Senior Dev Perspective

Use CHAR when:

  • Length is guaranteed fixed.

  • You want predictable storage.

Use VARCHAR otherwise.

Most real-world text fields? Use VARCHAR.


📅 Date vs DATETIME vs TIMESTAMP — Where Time Breaks Systems

Time is tricky.

Timezones are worse.


Example Table

CREATE TABLE people (
  name VARCHAR(100),
  birthdate DATE,
  birthtime TIME,
  birthdt DATETIME
);

What They Store

Type Stores
DATE Date only
TIME Time only
DATETIME Full date & time
TIMESTAMP Date & time

But here’s the important part.


DATETIME vs TIMESTAMP — The Critical Differences

Feature DATETIME TIMESTAMP
Storage 8 bytes 4 bytes
Timezone No auto conversion Timezone aware
Use case Historical data created_at / updated_at

TIMESTAMP auto-converts based on timezone settings.

DATETIME does not.


What Happens If You Choose Wrong?

Let’s say:

You store audit logs in DATETIME.

Your app runs in different timezones.

Suddenly:

  • Logs don’t align.

  • Reports shift hours.

  • Analytics dashboards look wrong.

You lose trust in your own data.

Timezone bugs are among the most common production issues I’ve seen.


Auto Tracking Example

CREATE TABLE captions (
  text VARCHAR(150),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE captions2 (
  text VARCHAR(150),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Perfect for metadata.


Senior Dev Perspective

Use:

  • DATE for pure dates.

  • DATETIME for historical records.

  • TIMESTAMP for metadata and audit fields.

  • Always standardize to UTC.

Time is hard. Don’t make it harder.


📆 Date & Time Functions — Reporting Power

Examples:

SELECT DAY(birthdate), MONTHNAME(birthdate), YEAR(birthdate) FROM people;
SELECT DATE_FORMAT(birthdate, '%a %b %D') FROM people;

Used for:

  • Monthly reports

  • Sales breakdowns

  • Business intelligence dashboards

Correct data types make these queries efficient.

Wrong ones make them painful.


3️⃣ Common Production Pitfalls

Let’s be honest.

We’ve all done at least one of these:

  • Used FLOAT for money

  • Used BIGINT everywhere

  • Used CHAR for user input

  • Ignored timezone handling

  • Stored dates as VARCHAR

Storing dates as VARCHAR is the ultimate “I’ll fix it later.”

You won’t.

You’ll migrate it painfully two years from now.


🛠 DevOps / SRE Angle

Data types affect:

  • Backup size

  • Replication speed

  • Query performance

  • Disk I/O

  • Index efficiency

Schema mistakes multiply at scale.

Fixing them later requires:

  • Downtime

  • Migrations

  • Risk

Choosing correctly early is cheaper.


🧠 Mental Model to Lock In

Data types are not academic details.

They are:

  • Performance decisions

  • Cost decisions

  • Reliability decisions

  • Legal decisions (finance)

Choosing correct types separates:

Tutorial developers
from
Production engineers


The Bridge Back

Remember the “small” performance issue that started this story?

We optimized indexes.

Replaced unnecessary BIGINT.
Switched FLOAT to DECIMAL.
Standardized timestamps to UTC.

Query times dropped.
Storage shrank.
Reports aligned.

The code didn’t change.

The schema did.

And that’s when it clicks:

Great backend engineers don’t just write logic.

They design storage with intention.

Because the database never forgets your mistakes.


More from this blog

Rajkumar Thangavel

19 posts

Tech enthusiast with nearly a decade of experience as a software developer across banking, telecom, healthcare and e-commerce. I share real-world learning, perspectives, and practical insights.