Databases 23 min read

Why Uber Switched from Postgres to MySQL: Scaling Lessons from a Real‑World Migration

Uber’s engineering team explains how Postgres’s immutable rows, write‑ahead logging, and replication design caused write amplification, upgrade pain, and data‑corruption risks, leading them to adopt a MySQL‑based Schemaless sharding layer that offers better buffering, connection handling, and replication semantics for massive scale.

ITPUB
ITPUB
ITPUB
Why Uber Switched from Postgres to MySQL: Scaling Lessons from a Real‑World Migration

Background

Uber originally ran a Python backend that persisted data in PostgreSQL. As the platform grew into a micro‑service architecture, the team found PostgreSQL’s design increasingly inefficient and replaced it with a MySQL‑based sharding layer called Schemaless .

PostgreSQL limitations

Low write‑throughput due to immutable row storage.

Poor data‑replication efficiency.

Table corruption issues.

Inadequate MVCC support on replicas.

Complex and time‑consuming upgrade process.

Disk format and tuple model

PostgreSQL stores each row as an immutable tuple identified by a ctid, which encodes the physical disk offset. Updating a row creates a new tuple with a new ctid, leaving the old version on disk until vacuum cleans it. Indexes store ctid values, so any update to a row forces updates to every index that references the tuple.

Example: a simple users table with primary‑key, name, and birth‑year indexes shows how a change to birth_year generates four physical writes – the new tuple, the primary‑key index entry, the name index entry, and the birth‑year index entry – each of which is also recorded in the write‑ahead log (WAL).

Write‑ahead log and replication

WAL records every physical change. When a row is updated, PostgreSQL writes four WAL entries, which are streamed to replicas. This “replication amplification” can consume significant bandwidth, especially across data‑center links.

During a crash, PostgreSQL replays WAL to bring the database back to a consistent state. If a replica falls behind, it must apply the same WAL stream, which can delay read queries.

Data corruption and upgrade challenges

In PostgreSQL 9.2, a bug caused some replicas to apply WAL entries out of order, leaving duplicate rows with different ctid s. Detecting and fixing the corruption required manual resynchronisation of each replica.

Upgrading between major PostgreSQL versions required a multi‑step process: shut down the master, run pg_upgrade, restart, take a fresh snapshot, restore the snapshot to each replica, and then catch the replicas up. This procedure took many hours for large datasets and could not be repeated frequently.

Why MySQL (InnoDB) was a better fit

InnoDB also supports MVCC but stores secondary index entries as pointers to the primary‑key value rather than a physical ctid. A secondary‑index lookup therefore performs two logical steps: find the primary key, then fetch the row. This design reduces the amount of data that must be rewritten on updates, because only the indexes that actually contain the changed column need to be modified.

InnoDB’s buffer pool is a user‑space LRU cache that avoids kernel‑space context switches, leading to lower latency than PostgreSQL’s reliance on the OS page cache.

MySQL uses a thread‑per‑connection model, which scales to tens of thousands of concurrent connections with modest overhead, whereas PostgreSQL spawns a separate process per connection, incurring higher memory and IPC costs.

MySQL replication operates at the logical statement or row level, producing compact binary logs that do not contain physical disk offsets. This results in smaller replication traffic and allows replicas to maintain true MVCC semantics, so read queries are not blocked by WAL replay.

Migration outcome

After migrating most of their workloads to MySQL (via Schemaless) and using NoSQL stores like Cassandra for special cases, Uber found the new stack far more resilient to growth, bandwidth constraints, and upgrade cycles. The team plans to share further advanced MySQL use‑cases in future posts.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

mysqlReplicationPostgreSQLdatabase migrationUberWrite Amplification
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.