By email: one hop in PostgreSQL, two descents in InnoDB
Every PostgreSQL index holds the row’s ctid, its page and slot. InnoDB stores rows in the primary-key tree; secondary indexes hold the key.
A random UUIDv4 primary key. In PostgreSQL it scatters only the primary-key index.
In InnoDB
It scatters the table itself: inserts split random pages and leave them half-empty. Use BIGINT or UUIDv7.
One update: PostgreSQL touches four indexes, InnoDB only the changed one
updated_at is indexed, so no HOT. PostgreSQL writes a new tuple; InnoDB edits in place, old value to undo.
Uber left PostgreSQL in 2016
Bad: So MySQL is simply faster
Their updates rewrote every index, so switch engines.
Good: One workload’s verdict
The post never mentions HOT, and InnoDB pays on every secondary lookup.
≈ 6 GB
worst-case query memory, 300 PostgreSQL connections
Each connection is a process, and each sort or hash gets its own memory. Pool with PgBouncer; keep backends near the core count.
T1 locks doctor 7’s slots 10–12. Can T2 insert 11?
At their defaults, PostgreSQL locks only the rows it returned, so 11 slips in. InnoDB also locks the gaps; T2 waits.
Most apps run fine on either. Break ties in order.
- Team first: what your on-call already runs well
- PostGIS, pgvector, jsonb, partial indexes → PostgreSQL
- Vitess, or update-heavy indexed rows → MySQL
- Otherwise PostgreSQL, behind PgBouncer
Remember
Default to PostgreSQL behind PgBouncer, and name what would switch you: a MySQL team, Vitess, or update-heavy indexed rows.