はじめに
「MySQLのPrimaryKeyはUUIDv4じゃなくて、UUIDv7とかULIDを使った方がいい」と耳にしました。
本記事では、UUIDv4とUUIDv7の違いを踏まえ、MySQLのデータ保存構造との相性について解説します。
UUIDとは
UUID(Universally Unique IDentifier)は、128ビットの値で空間と時間を超えた一意性を保証する識別子であり(RFC9562)、被りの無い値を用いたい時に利用します。
2025年5月現在 v1-v8までの種類が存在し、主にUUIDv4とUUIDv7が広く用いられています(他のバージョンは下位互換だったり実験的な状態だったり)。
こんな値
3494f92e-7c4f-9220-36b1-cda6df05255c
721a246e-a7fb-edd1-f45a-a86ce9214913
dfdcf7a6-6849-f547-147e-abbc7f2f7d1b
UUIDv4
完全にランダム(または疑似乱数)で生成されるUUID
UUIDv7
タイムスタンプを表すフィールドを含むUUID
最初の12桁が時間を表すフィールドになっており、1970年1月1日午前0時(UTC)からの経過ミリ秒数を16進数で表しています
UUIDv4: 完全ランダム
UUIDv7: 時系列項目を含む
UUIDをPrimaryKeyに用いるモチベーション
MySQLでは一般的にAutoIncrementがPrimaryKey(PK)に用いられますが、UUIDには以下のような利点があります。
PKがUUIDの場合とAutoIncrementの場合の例
IDをAutoIncrementで生成した場合
ID | Name | Price |
---|---|---|
1 | みかん | 100 |
2 | りんご | 200 |
3 | いちじく | 800 |
IDをUUIDで生成した場合
ID | Name | Price |
---|---|---|
d837cb33-0462-b68b-40ae-5e1b4d4df04e | みかん | 100 |
976a3cd6-8860-de34-5285-76b8ad2b420b | りんご | 200 |
ae648c87-029e-0100-1e15-3099e7180848 | いちじく | 800 |
1. 余計な情報が洩れにくい
例えばUserIDがAutoIncrementの場合、もしそのIDをユーザーが確認できると、自分が何番目のユーザーであるか(このサービスは現在何人が利用しているか)を認識することができてしまいます。
UUIDであれば明確な順序はないためこのような心配が軽減されます。
2. テーブルの統合が容易
複数のテーブル(例:UserAとUserB)を後から結合する際、Auto IncrementだとID衝突の懸念がありますが、UUIDならほぼ衝突がありません。
3. アプリケーション側でPKの値を決定できる
AutoIncrementは基本的にDBにレコードが生成される際に決定されます。その一方で、(UUIDに限りませんが)アプリケーション側でPKを決めることができれば、親レコードをデータベースへ保存する前に、そのレコードのPKを子レコードに設定することができます。
MySQLのデータ保存方法がUUIDv4と相性が悪い
UUIDv4をDBのPKとして利用すべきでない理由は、MySQLのデータの保存方法と相性が悪いためです。
MySQLのデータの保存方法
MySQLのストレージエンジンでは、データは「ページ」と呼ばれる単位で保存され、PKをソート順に並べたクラスタインデックスで管理されます(下図参照)。そして、データの読み込みはページ単位で行われ、書き込み時には対応するページに追加/更新し、容量オーバー時にはページ分割(スプリット)を行います。
MySQLは以下の特徴を持つ
- PrimaryKeyの順番でデータを保存
- データの読み書きはPrimaryKeyの範囲(ページ)毎に行う
UUIDv4とUUIDv7の性能比較
MySQLには上記のような特徴があるため、INSERTの際に、UUIDv4(完全ランダム)であれば複数のページに分散して書き込み、UUIDv7(時系列性のあるランダム)であれば、ほぼ同じ範囲のページに書き込むことができます。
従って、PKはUUIDv4ではなくUUIDv7を利用した方がIO効率が高いのです。
どのくらい効率が変わるのか?
こちらの記事によると、約2800万のレコード挿入では、UUIDv4を用いた場合、UUIDv7に比べ70時間長く実行時間がかかるようです(下図)
まとめ
UUIDv4はMySQLのデータ保存方法とマッチしておらずクエリパフォーマンスが低下する点で利用を控えるべきであり、代わりに時系列性を持つ識別子であるUUIDv7(やULID)を利用するのがおすすめです。
参考文献