Skip to main content
sql-db

MySQL

The world's most-deployed open-source relational database — clustered PK index, InnoDB MVCC, Vitess for sharding at billions-of-rows scale.

Why it exists

MySQL (specifically InnoDB, the default storage engine since MySQL 5.5) is the most-deployed relational database on the internet. It powers Facebook, GitHub, YouTube, Airbnb, Uber, Shopify, and thousands of others. Its combination of a clustered primary-key index, mature MVCC, best-in-class replication, and the Vitess sharding layer makes it the default relational DB for consumer-facing internet products at every scale from startup MVP to planetary.

How it works

MySQL InnoDB stores rows INSIDE the primary-key B+tree (clustered index) — the leaf pages contain the actual row data, not a pointer to a heap. This means a PK lookup like `SELECT ... WHERE pk = ?` is 1 disk I/O for warm data, not 2. MVCC is implemented via undo tablespaces: on each modification, the previous row version goes to undo; readers reconstruct their snapshot from undo. The redo log (InnoDB's Write-Ahead Log) captures every change before disk; `innodb_flush_log_at_trx_commit=1` gives full ACID durability. Buffer pool sized to 70-80% of RAM holds the hot working set — very different from Postgres's 25% philosophy. Replication is via binlog (statement-based, row-based, or mixed) — async by default, semi-sync opt-in for read-your-writes. GTID (Global Transaction ID) tracks replication position robustly across failovers.

Scaling characteristics

A well-tuned MySQL m6i.large (2 vCPU, 8 GB RAM, InnoDB buffer pool sized to 6 GB) handles ~20-25K point-lookup QPS at 60-70% CPU with a 90% warm buffer pool hit rate. Writes cap at ~5-10K QPS on Multi-AZ semi-sync (dominated by cross-AZ commit round-trip). Read scaling: async binlog-replicated read replicas — each additional replica adds ~20K reads at some staleness. Write scaling: Vitess (YouTube-tested), the horizontal-sharding layer that gives you routing, resharding without downtime, and cross-shard query planning. Vitess powers Slack (thousands of shards), GitHub (moving to Vitess in 2023), HubSpot, and Cash App. Storage: single-instance managed MySQL scales to ~64 TB (Aurora MySQL); sharded Vitess fleets scale to petabytes.

When to use it

  • Point-lookup-dominant workloads where the clustered PK index gives you 1 I/O per read (URL shorteners, user profile lookups, cart lookups)
  • You need Vitess for L6+ sharding — the most mature horizontal-sharding layer in the SQL world
  • You're on AWS and want Aurora MySQL (write-optimized shared-storage cloud-native flavor)
  • Team is familiar with MySQL / your existing app stack (Rails, Django ORM, Laravel) speaks MySQL
  • Consumer-facing products with cost sensitivity and moderate write volume — MySQL RDS is significantly cheaper than DynamoDB above ~1M requests/day

When NOT to use it

  • You need PostGIS-quality geospatial queries — MySQL Spatial is less mature
  • You need pgvector-quality vector similarity — Postgres or a dedicated vector DB is stronger
  • You need extension richness (hstore, pgvector, tsvector for full-text, TimescaleDB) — Postgres is the ecosystem winner
  • You need a JSONB with GIN indexes for a document-heavy workload — Postgres JSONB is more mature than MySQL JSON
  • You need >100K writes/sec sustained without sharding investment — consider Cassandra or a wide-column store

Failure modes

  • Primary DB down → automatic failover to a Multi-AZ standby (~30-90s outage window on RDS)
  • Replication lag on binlog under heavy write pressure → replicas serve stale data; write-then-read from the same session fails read-your-writes
  • Long-running SELECT holds an old snapshot → InnoDB undo log grows; disk pressure and increased purge lag
  • Bad query without a covering index → clustered PK still helps but a secondary-index lookup requires PK dereference (still 2 I/Os)
  • Connection storm → 'too many connections' errors; mitigate with ProxySQL, RDS Proxy, or HikariCP-style pooling
  • `innodb_buffer_pool_size` too small → high cold-hit rate, latency spikes as buffer pool churns
  • Vitess resharding under load → temporary lookup latency spikes as vindexes rebuild; must be planned during low-traffic windows

Alternatives

  • PostgreSQL — richer type system + extensions (PostGIS, pgvector), but 2 I/Os per cold PK lookup vs MySQL's 1; Citus for sharding is less mature than Vitess
  • Aurora MySQL — MySQL-compatible cloud-native shared-storage flavor with 5x-15x more read replicas and near-zero failover; higher cost
  • TiDB — MySQL-wire-compatible NewSQL with horizontal scale built in; ~2x cost vs sharded MySQL
  • PlanetScale — Vitess-as-a-service; excellent developer experience, generous free tier, but paid tier cost accumulates at scale
  • CockroachDB — Postgres-wire-compatible; different DB entirely but often compared for global multi-region use cases

Interview questions

  • Explain the clustered index — why does MySQL InnoDB give you 1 I/O per PK lookup where Postgres gives you 2?
  • You're at 10K writes/sec on a single MySQL primary. What breaks first — CPU, disk IOPS, or replication?
  • How does Vitess route a query — walk through VTGate, VTablet, and VSchema.
  • What's the difference between binlog_format=STATEMENT vs ROW vs MIXED, and when does each matter?
  • Your read replica lag is 30 seconds during peak. What are the 3 most likely causes?
  • You want to add a new NOT NULL column to a 100 GB table with zero downtime. How do you do it?
  • How would you size `innodb_buffer_pool_size` for a workload with 200 GB dataset but 10 GB hot set?
  • Explain the difference between REPEATABLE READ (MySQL default) and SERIALIZABLE and when you'd want SERIALIZABLE.