似たような話は各所にあるのですが、自分の理解向け、備忘録向けに書きます。
UUID について
もとの起こりはWikipediaなどを見るとして、実運用的には開発時にデータに一意なIDを割り振る際によく用いられる。
UUIDには複数のバージョンがあり、最も開発で用いられていると思われるのは UUIDバージョン4(ランダム生成) 、その他に バージョン1(MacアドレスやTimestamp情報を用いて生成) などがある。
ビット幅は 128ビット(16バイト) で、文字列表現では16進法で以下のような形で表現する。
(32バイト+バウンダリ4バイト=36バイト。 "-" がバウンダリ文字列)
550e8400-e29b-41d4-a716-446655440000
SQL を用いて 16バイトで MySQL に保存する (8.0 以前 )
MySQL に16バイトで保存する場合には、16進数の文字列表現のUUIDからバウンダリ文字列を取り除いたものを、Binary に変換して保存する、という流れになります。
それを SQL で表現すると以下のような形になります。
CREATE TABLE `sada ` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`UUID VARBINARY(16) NOT NULL,
`name` VARCHAR(1024) NOT NULL,
PRIMARY KEY (`id`)
)
ENGINE = InnoDB,
CHARACTER SET = `utf8mb4`, COLLATE = `utf8mb4_bin`;
INSERT INTO sada (
uuid,
name
)
VALUES(
UNHEX(REPLACE('550e8400-e29b-41d4-a716-446655440000', '-', '')),
'masashi'
);
SQL を用いて 16バイトで MySQL に保存する (8.0 以後 )
MySQL 8 以降から、UUID を操作するための関数が追加されています。
8 以降を使用している場合はこれを使うとオレオレ感を感じる独自処理から脱却することができます。
- UUID_TO_BIN (UUID文字列をBinaryに変換)
- BIN_TO_UUID (BinaryをUUID文字列に変換)
例は上記公式ブログを引用します。
CREATE TABLE t (id binary(16) PRIMARY KEY);
INSERT INTO t VALUES(UUID_TO_BIN(UUID()));
Query OK, 1 row affected (0,00 sec)
#a few inserts later..
SELECT BIN_TO_UUID(id) FROM t;
+--------------------------------------+
| BIN_TO_UUID(id); |
+--------------------------------------+
| 586bcc2d-9a96-11e6-852c-4439c456d444 |
| 5942e49a-9a96-11e6-852c-4439c456d444 |
| 841ae775-9a96-11e6-852c-4439c456d444 |
| 84393c8e-9a96-11e6-852c-4439c456d444 |
| af0f27e2-9aad-11e6-852c-4439c456d444 |
+--------------------------------------+
5 rows in set (0,00 sec)
Java / Kotlin を用いて 16バイトで MySQL に保存する
プログラムからも、各言語で生成した UUID 情報を Binary することで 16 バイトにおさめて保存することが出来ます。
ここでは Kotlin の例のみを記載します。
Java / Kotlin には UUID クラスが存在するので、以下のように UUID型 -> Byte 配列、ならびに Byte 配列 -> UUID型 の変換ロジックを作成し、使用する環境(ORM等)にあわせて組み込めば OK です。
fun uuidToBytes(uuid: UUID): ByteArray {
val buffer = ByteBuffer.allocate(16)
buffer.putLong(uuid.mostSignificantBits)
buffer.putLong(uuid.leastSignificantBits)
return buffer.array()
}
fun bytesToUuid(bytes: ByteArray?): UUID? {
if (bytes == null) {
return null
}
val buffer = ByteBuffer.wrap(bytes)
return UUID(buffer.long, buffer.long)
}
Appendix. より省サイズの ID 表現
UUID は 16 バイトもあるかなり大きめな ID 表現となるので、 UUID の保存で省サイズ化を頑張るより、より省サイズの ID を採用するという手もあると思います。
以下は参考文献程度に。