1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MySQLのPrimaryKeyでUUIDv4を利用するのはやめた方がいい

Posted at

はじめに

「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進数で表しています

uuidv7.png

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の範囲(ページ)毎に行う

clusterdIndex.png

UUIDv4とUUIDv7の性能比較

MySQLには上記のような特徴があるため、INSERTの際に、UUIDv4(完全ランダム)であれば複数のページに分散して書き込み、UUIDv7(時系列性のあるランダム)であれば、ほぼ同じ範囲のページに書き込むことができます。
従って、PKはUUIDv4ではなくUUIDv7を利用した方がIO効率が高いのです。

無題のプレゼンテーション(1).png

どのくらい効率が変わるのか?

こちらの記事によると、約2800万のレコード挿入では、UUIDv4を用いた場合、UUIDv7に比べ70時間長く実行時間がかかるようです(下図)

まとめ

UUIDv4はMySQLのデータ保存方法とマッチしておらずクエリパフォーマンスが低下する点で利用を控えるべきであり、代わりに時系列性を持つ識別子であるUUIDv7(やULID)を利用するのがおすすめです。

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?