はじめに
いつもユニークな ID に UUID を使っているのですが、他には何かあるのでしょうか?
気になったので調べてみました!
紹介するもの
この記事ではこれらを紹介します
利用数
npm のDL数を2022年の月別で比べてみます。グラフは npm-stat を使わせていただきました。
UUID と NanoID がよく使われているようです。
UUID が NanoID の 3倍、NanoID が CUID の30倍使われています。
UUID と NanoID を除くと以下のようになりました。
それぞれの特徴
UUID がとても使われているのはわかりました。続いて、それぞれの特徴を紹介します。
UUID
まずはみんな大好き UUIDです!ここではメジャーなバージョン4を紹介します。
UUIDバージョン4 は16進数の文字32個で構成されています。ひとつのUUIDにつき128ビットありますが、そのうち6ビット (1文字と半分) を規格で使っています。
形式は以下です。
RRRRRRRR-RRRR-4RRR-rRRR-RRRRRRRRRRRR
※Rがランダム、4が固定、rが2ビットだけ固定
6ビットを使っているので、122ビットが乱数になりますね。つまり $2^{122} \approx 5.3×10^{36}$ 通りの UUID が存在することになります。
衝突確率について、衝突するまでの生成回数の期待値は $2^{122/2} \approx 2.3*10^{18}$ 個となります。まず衝突しないですね。
参考:誕生日攻撃
NanoID
次は NanoID です!
NanoID はUUIDの問題とされていた、「生成結果の文字列が長い」ことを解決したものです。
UUID が36文字なのに対し、NanoID は21文字です。かなり短くなりましたね。
また、ランダム部分が 126ビットあって UUID の122ビットと比べて少し強固です。
形式です。
V1StGXR8_Z5jdHi6B-myT
生成速度が気になっていたのですが、NanoID の作者がまとめてくださっていました。ありがたい。
$ node ./test/benchmark.js
crypto.randomUUID 21,119,429 ops/sec
uuid v4 20,368,447 ops/sec
@napi-rs/uuid 11,493,890 ops/sec
uid/secure 8,409,962 ops/sec
@lukeed/uuid 6,871,405 ops/sec
nanoid 5,652,148 ops/sec
customAlphabet 3,565,656 ops/sec
secure-random-string 394,201 ops/sec
uid-safe.sync 393,176 ops/sec
cuid 208,131 ops/sec
shortid 49,916 ops/sec
ULID
続いてULIDです!
ULID は、UUIDの問題を解消したものとなっています。
ULID が解消した UUIDの問題は 「生成結果の文字列が長い」「ソートできない」 です。
そう。ULIDは生成時間でソートできるのです。よさそうですね。
形式は以下です。
01AN4Z07BY79KA1307SR9X4MV3
※前半48bit がtimestamp で、後半80bit がランダムです。
前半に timestamp があるからソートできるんですね!また、16進数ではなく英数字を使うことで UUID よりも文字数が減っています。
タイムスタンプは西暦 10889年まで対応しています。未来永劫つかえる UUID に比べると短い期間ですが、それでも十分でしょう。
UUID に比べてランダム部分のbit数が少ないですが、同じミリ秒内に $1.21*10^{24}$ 個までの生成であればソート可能性が保たれるとのことです。timestamp がミリ秒単位で変わるので、こちらも実用上は問題なさそうですね。
CUID
最後にCUIDです!
CUID は UUID の問題を解決しながら、ULID よりも良いとされているものです。
ULID との具体的な違いはこちら https://github.com/paralleldrive/cuid/issues/103
まずは形式です。
ch72gsb320000udocl363eofy
分解するとこうなります。 c - h72gsb32 - 0000 - udoc - l363eofy
c
: 固定値
h72gsb32
: timestamp
0000
: Counter
udoc
: クライアントのfingerprint
l363eofy
: ランダム
です。UUID や ULIDに比べていろいろありますね。
CUID の特徴です。
- スケーラブル
- fingerprintがあるので、複数のクライアント間では衝突しない
- 水平方向のスケーラビリティができる
- パフォーマンスが良い
ULID に比べてランダム部が小さいですが、同じミリ秒内に10000までの生成であればソート可能性が保たれます。同じくtimestamp がミリ秒で変わるので、実用上は問題ないことがほとんどだと思います。
ソースを見てみると、非推奨となっている String.prototype.substr()
が使われていました。要注意かも?
さいごに
私は UUID しか知らなかったのですが、生成順でソートできるのは良さそうですね!
それぞれの利点と欠点を知って、使いわけるのはかなりアリだなって思いました。