TL;DR
- UUID v4 を主キーにすると、MySQL でも PostgreSQL でも、レコード数が増えるほどシーケンシャル ID より遅くなる。
- 一般的な Web アプリケーションでは大きな問題にならない。性能を重視するなら、タイムスタンプを含む UUID v7 などを選ぶ。
内容
動画を要約ツールで要約した内容をもとにまとめた。
UUID とシーケンシャル ID の比較
MySQL と PostgreSQL でベンチマークを取り、シーケンシャル ID と UUID v4 を比べている。レコード数が増えるほど差は大きくなり、PostgreSQL のほうが差が目立つ。MySQL では 400 万レコードを超えたあたりで差がはっきりし、1 回のインサートにかかる時間はシーケンシャル ID が約 0.1 ms、UUID v4 が約 0.5 ms と、約 5 倍の差が出た。インサートだけでなくセレクトでも UUID v4 のほうが遅い。ただし、一般的な Web アプリケーションでは大きな問題にならない。
UUID v4 が遅い理由
UUID v4 はランダムに生成されるので、データが順序付けられずに分散し、ディスク I/O やメモリキャッシュの効率が落ちる。シーケンシャル ID なら挿入は常に末尾に行われるが、UUID v4 は挿入位置がばらばらになり、インデックスのページ分割が頻繁に起きる。また、UUID を 36 文字の文字列で持つと数値型よりずっと大きく、インデックスも大きくなる。
MySQL と PostgreSQL で差が違う理由
MySQL はデータとインデックスを同じファイルに持つクラスタードインデックスを使うので、インデックスの更新に合わせてデータも動かす必要がある。PostgreSQL はデータとインデックスを別のファイルに持つ。PostgreSQL では、メモリ上のデータをディスクに書き込むチェックポイントの頻度が多いと書き込みが遅くなり、動画のベンチマークでもこの設定が差に影響していた。
UUID のバージョンの選び方
UUID にはバージョン 1、4、7 などがあり、生成方法が違う。
- 性能を重視するなら、タイムスタンプを含む v1 か v7 を選ぶ。シーケンシャルに近い値になるので、大量のデータでも性能が安定する
- 一意性と予測できないことを重視するなら、完全にランダムな v4 を選ぶ。公開する API キーのように、外部から推測されては困る ID に向いている
- v7 は高い一意性とタイムスタンプによる順序を両立するので、性能と一意性のバランスが取れている
キーワード
- UUID
- MySQL
- PostgreSQL
- クラスタードインデックス
自分の理解
社内で話題に挙がっていたので、Video Summarizer で要約させた。