UUIDというデータ型を初めて知ったのでどういうものか調べてみました。
UUID (Universally Unique Identifier)とは
Universally ... 普遍的な
Unique ... 固有の
Identifier ... 識別子
日本語にすると汎用一意識別子となります。
DBテーブルの主キーやユニークキーなど、データを単一に識別するために使用されます。
UUIDは128bit(16byte)の値を16進数で表現したものです。
例:
550e8400-e29b-41d4-a716-446655440000
UUIDは下記のような形式で表現されます(一般的な表記)。
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
- M ... バージョン(生成方法)
- N ... 種別(UUIDの種類を示す固定ビット)
※種別はUUIDの中に埋め込まれた固定ビットで、
UUIDの構造(どの規格のUUIDか)を判別するための情報です。
連番(Autoincrement)と比べて何が良いのか
データを一意に特定するための値として一番考えやすいのが連番(Autoincrement)だと思います。
「連番の方がわかりやすくて良いじゃないか」とも思ったのですがそうでもないようです。
推測されない
UUIDはハッシュや乱数を含む値を使用しているので連番に比べて推測されにくいです。
Primary KeyやUnique Key を指定したデータは場合よってはURI等としてユーザに見える形で使用されます。
そうすると、/page?id=3というURIが存在する場合/page?id=1や/page?id=4等が存在するだろうということを簡単に推測できてしまいます。
直ぐに問題にはならないかもしれませんが不用意にデータの規則性を公開するのは得策ではありません。
他にもスクレイピングしやすい等の問題が発生するようですが、
正直、個人開発レベルであればあまり考慮する必要はない気もします....
DBに依存せず生成できる
連番(Autoincrement)はDB内部のカウンタで管理されているため、
IDを生成するにはそのDBにアクセスする必要があります。
これに比べてUUIDはDBの値に依存していないため、外部で生成してDBに登録ということができます。
これによりDBのロック時間を少なくし、アクセス集中時のパフォーマンス向上に役立ちます。
DB登録前にIDを割り振ることができるため、分散型システムにおいて複数箇所で同時にIDを生成することができます。
(Gitのコミットに付与されるハッシュのようなイメージ)
デメリット
UUID最高!と思ってもう少し調べると多少デメリットもあるようです。
データサイズの増加
UUIDは128bit(16byte)の値です。
多くのDBではUUID専用型やBINARY(16)として保存されますが、
Autoincrementの整数(4〜8byte)と比べるとデータサイズは大きくなります。
その結果、
- インデックスが大きくなる
- キャッシュに載せられる件数が減る
- ディスクI/Oが増える
といった理由から、検索・ソート・INSERT性能に影響が出る場合があります。
可読性が落ちる
UUIDは連番(Autoincrement)に比べてデータを閲覧した際の可読性が落ちます。
データを目で見て順番を判断したり、同一データを探すのは難しいかもしれません。
DBの値を直接参照してSQLを発行したい場合などは不便を感じるかもしれません。
UUIDのバージョンと特徴
| Version | 特徴 | 今使うべき? |
|---|---|---|
| V1 | 時刻 + MAC | × |
| V2 | UID/GID | × |
| V3 | MD5 hash | △ |
| V4 | 完全ランダム | ◎ |
| V5 | SHA-1 hash | ○ |
| V6 | v1改良版 | ○ |
| V7 | 時刻 + 乱数 | ◎ |
| V8 | カスタム | △ |
UUID V1
タイムスタンプとMacアドレスを使用したUUIDです。
タイムスタンプが下位から並んでいるのでUUIDのみでソートする際には計算が必要になります。
今から採用する場合はV6を使用することが推奨されています。
形式
- 0~31bit ... タイムスタンプ
- 下位32bit (
1582/10/15 00:00:00からの経過時間(100ns単位))
- 下位32bit (
- 32~47bit ... タイムスタンプ
- タイムスタンプの中
- 48~51bit ... UUIDのバージョン
-
1固定
-
- 52~63bit ... タイムスタンプ
- タイムスタンプの上位
- 64~65bit ... 識別子
- UUIDの種類を表す
- とりあえず
0x8~0xBを使用しておけば良さそう(他の領域は予約済み)
- 66~79bit ... クロックシーケンス
- ランダム値で初期化した連番
- 80~127bit ... Macアドレス(IEEE802アドレス)
- Macアドレスがなければランダムな値を入れる
- ※セキュリティの観点からMACアドレスではなく乱数が使用されることが多い
UUID V2
V1のタイムスタンプの下位の一部を削除し、グループIDやユーザIDといった作成者の情報を付与したものです。
現状、あまり使用されいないらしいです。
情報もあまり見つかりませんでした...
UUID V3
MD5を使用したハッシュ値で構成されます。
ハッシュ値なので、同じキーからは同じ値が生成されます。
今回のようなDBのキーとして使用したい場合、ハッシュのキーとなる値に一意性を担保する必要があるので、あまり活用方法がないように思います。
(一応、活用できるユースケースもあるようです。)
形式
- 0~47bit ... MD5
- MD5のハッシュ値の上位
- 48~51bit ... バージョン
-
3固定
-
- 52~63bit ... MD5
- MD5のハッシュ値の中
- 64~65bit ... 識別子
- UUIDの種類を表す
- とりあえず
0x8~0xBを使用しておけば良さそう(他の領域は予約済み)
- 66~127bit ... MD5
- MD5ハッシュ値の下位
UUID V4
一番よく見るバージョンです。
バージョンを表す4bit以外は全て乱数又は疑似乱数になります、
生成するアルゴリズムは指定されていないようです。
値が全てランダムなので順番は気にしなくて良いです。
形式
- 0~47bit ... 乱数A
- 任意のアルゴリズムで生成した乱数または疑似乱数
- 48~51bit ... バージョン
-
4固定
-
- 52~63bit ... 乱数B
- 任意のアルゴリズムで生成した乱数または疑似乱数
- 64~65bit ... 識別子
- UUIDの種類を表す
- とりあえず
0x8~0xBを使用しておけば良さそう(他の領域は予約済み)
- 66~127bit ... 乱数C
- 任意のアルゴリズムで生成した乱数または疑似乱数
UUID V5
V3とほとんど同じ、
ハッシュ生成のアルゴリズムがSHA-1になります。
形式
- 0~47bit ... SHA-1
- SHA-1のハッシュ値の上位
- 48~51bit ... バージョン
-
5固定
-
- 52~63bit ... SHA-1
- SHA-1のハッシュ値の中
- 64~65bit ... 識別子
- UUIDの種類を表す
- とりあえず
0x8~0xBを使用しておけば良さそう(他の領域は予約済み)
- 66~127bit ... SHA-1
- SHA-1ハッシュ値の下位
UUID V6
構成はほとんどV1と同じ。
V1のタイムスタンプが下位から始まっているためソートができない問題を解消したバージョン
新しくUUIDを取り入れる場合はV1でなくV6を使用するように推奨されている。
形式
- 0~31bit ... タイムスタンプ
- 上位32bit (
1582/10/15 00:00:00からの経過時間(100ns単位))
- 上位32bit (
- 32~47bit ... タイムスタンプ
- 中16bit
- 48~51bit ... UUIDのバージョン
-
6固定
-
- 52~63bit ... タイムスタンプ
- 下位12bit
- 64~65bit ... 識別子
- UUIDの種類を表す
- とりあえず
0x8~0xBを使用しておけば良さそう(他の領域は予約済み)
- 66~79bit ... クロックシーケンス
- ランダム値で初期化した連番
- 80~127bit ... Macアドレス(IEEE802アドレス)
- Macアドレスがなければランダムな値を入れる
- ※セキュリティの観点からMACアドレスではなく乱数が使用されることが多い
UUID V7
V1,V6では1582/10/15 00:00:00からの経過時間(100ns単位)を使用していましたが、
V7では1970/01/01 00:00:00からの経過時間(1ms秒精度)である UNIXエポックタイム を使用しています。
形式
- 0~47bit ... UNIXタイムスタンプ
-
1970/01/01 00:00:00からの経過時間(1ms)
-
- 48~51bit ... UUIDのバージョン
-
7固定
-
- 52~63bit ... 乱数A
- 任意のアルゴリズムで生成した乱数または疑似乱数
- 64~65bit ... 識別子
- UUIDの種類を表す
- とりあえず
0x8~0xBを使用しておけば良さそう(他の領域は予約済み)
- 66~127bit ... 乱数B
- 任意のアルゴリズムで生成した乱数または疑似乱数
UUID V8
バージョンと識別子を除いた全てのビットを自由に設定できます。
UUIDのフォーマットを使用したいが、他のバージョンでは不都合な場合などに使用されます。
例えば以下のようなケースが考えられます。
- 他のUUIDバージョンで指定されていない情報を埋め込む必要がある
- 他のアプリケーションや言語の制約により他のUUIDバージョンが使用できない
形式
- 0~47bit ...自由実装
- 48~51bit ... UUIDのバージョン
-
8固定
-
- 52~63bit ... 自由実装
- 64~65bit ... 識別子
- UUIDの種類を表す
- とりあえず
0x8~0xBを使用しておけば良さそう(他の領域は予約済み)
- 66~127bit ... 自由実装
結論 (結局どれを選べば良いの?)
新規開発の場合
基本は UUID v7 を選択しておけば問題ありません。
時系列順に並ぶためDBとの相性が良く、
現在もっともバランスの良いUUIDです。
手軽さ・互換性重視の場合
標準ライブラリのみで生成したい場合は
UUID v4 を選択すると良いでしょう。
最後に
AI駆動開発をしていたところDBのデータ型をUUIDなるものに指定されました。
聞いたことのないデータ型だったので少し調べてみました。
他の方の助けになれば幸いです。
参考文献






