CONCEPT
UUID string representation in MySQL¶
MySQL has no native UUID column type; UUIDs in MySQL are
stored as 36-character strings (VARCHAR(36)) or as
16-byte BINARY(16) with application-side formatting.
Postgres has a native 16-byte UUID column. The asymmetry
affects storage footprint, primary-key behaviour, and
migration plans.
The UUID data type is essentially a 36 character long string. So we can set this data type to a
varchar(36)in MySQL. MySQL also supports generating UUID's via aUUID()function, so when it comes to adding new records, we could utilize theUUID()function that behaves similarly to Postgres'sgen_random_uuid()function.—
Generation¶
| Postgres | MySQL |
|---|---|
gen_random_uuid() |
UUID() |
Returns UUID type |
Returns VARCHAR text |
Storage choices in MySQL¶
VARCHAR(36)— human-readable, easy to debug, 36 bytes per key. The path the PlanetScale post recommends as the drop-in.BINARY(16)— compact, 16 bytes per key. Requires application-side or helper-function conversion (UUID_TO_BIN,BIN_TO_UUIDin MySQL 8.0+). Matches the storage footprint of Postgres's native UUID.CHAR(36)— fixed-width, equivalent in practice toVARCHAR(36)for UUIDs.
Interaction with clustered-index primary keys¶
InnoDB organises tables as B+trees keyed
by the primary key. Using a random UUID as a VARCHAR(36)
primary key triggers the full
concepts/uuid-primary-key-antipattern — random insert
points, write amplification, and non-sequential scans —
and amplifies it further by ~2.25× the key bytes compared
to BINARY(16).
Migration plans that move Postgres UUID-keyed tables to MySQL have two good exits:
- Keep UUIDs, switch to
BINARY(16)— preserves the opaque-identifier contract, minimises the storage penalty. - Move off UUIDs in the migration window — introduce
a
BIGINT AUTO_INCREMENTinternal key, keep the UUID as a secondary unique index for external contract. See patterns/sequential-primary-key.
Seen in¶
- — Brian Morrison II (PlanetScale, 2024-03-19) canonicalises
the byte-wise storage ratios:
CHAR(36)= 288 bits = 9× a 32-bitINT;BINARY(16)= 128 bits = 4×INT. Adds the MySQL 8.0+UUID_TO_BIN/BIN_TO_UUIDhelper functions (with the optional swap flag — see concepts/uuid-to-bin-swap-flag) as the canonical path for converting between representations, with a worked SQL example. - — Adnan Kukic (PlanetScale, 2023-02-09) canonicalises
VARCHAR(36)as the drop-in mapping for Postgres's nativeUUIDtype during cross-engine migrations, with theUUID()generator function as equivalent ofgen_random_uuid().
Related¶
- concepts/uuid-primary-key-antipattern — the full cost breakdown of random-UUID primary keys on InnoDB.
- concepts/uuid-version-taxonomy — v1–v8 layouts
- concepts/uuid-to-bin-swap-flag — MySQL 8.0+
UUID_TO_BIN(@u, 1)COMB-UUID helper for v1 values - concepts/cross-engine-sql-data-type-equivalence
- systems/mysql, systems/postgresql
- patterns/sequential-primary-key
- patterns/cross-engine-database-migration-audit