[MySQL]UUIDをバイナリ変換する
2024/04/09
MySQLでUUID文字列をバイナリ変換してレコードに格納する方法と、
逆にレコード取得する際にバイナリをUUID文字列に変換する方法のメモです。

やり方
対象のカラムの型をvarbinary(16)で定義。
INSERTする際に、生成したUUID文字列をUUID_TO_BIN関数を利用してバイナリに変換。

mysql> CREATE TABLE test (bin varbinary(16) NOT NULL, PRIMARY KEY(bin));
Query OK, 0 rows affected (0.07 sec)
mysql>
mysql> INSERT INTO test VALUES (UUID_TO_BIN('222F8975-14F8-4D0A-BA2E-86C054BE493C'));
Query OK, 1 row affected (0.04 sec)

SELECTする際に、とくに何も指定していなければバイナリ文字列が取得されるので、
BIN_TO_UUID関数で該当のカラムをUUID文字列に変換して取得。

mysql> SELECT * FROM test;
+------------------------------------+
| bin |
+------------------------------------+
| 0x222F897514F84D0ABA2E86C054BE493C |
+------------------------------------+
1 row in set (0.02 sec)

mysql> SELECT BIN_TO_UUID(bin) FROM test;
+--------------------------------------+
| BIN_TO_UUID(bin) |
+--------------------------------------+
| 222f8975-14f8-4d0a-ba2e-86c054be493c |
+--------------------------------------+
1 row in set (0.01 sec)

注意点
UUID_TO_BIN関数とBIN_TO_UUID関数はMySQL8からの機能です。

UUIDをバイナリ変換するメリット
まずなぜUUIDを使うのか
UUIDをPRIMARY KEYに利用した場合は、連番を使わずともランダムな文字列でほぼ一意なIDを生成できます。
※厳密には、2128通り(UUIDv4なら2122通り)の範囲で生成するので天文学的な確率で衝突はあり得ます

連番IDをURLに表出するケースがある場合は、非公開リソースURLを推測されたり、
それがユーザIDとなっている場合はおおよその数が推測される可能性があります。
これはセキュリティ的な観点で避けるべきです。

ランダム文字列であるUUIDを利用することでそのような推測を回避し、セキュリティ性を向上できます。

UUIDを利用するデメリット
正直、曖昧な理解ですがざっくりいうと、
インデックスを連番にするとインデックス検索の効率が良くなり、
キャッシュの恩恵を受けやすく、ディスクへのI/Oが減ります。

インデックスをUUIDにする場合はその逆で、インデックス検索の効率が落ちるため、ディスクへのI/Oが増えます。
その結果、パフォーマンスが落ちてしまいます。

UUIDをバイナリ変換するメリット
UUIDはそのまま文字列にすると32文字(32byte)ですが、バイナリ変換することで16byteまで容量を削減できます。
これによりインデックスの保持に必要な容量が減り、パフォーマンスが改善されます。

そのため、UUIDをそのまま利用するのではなく、バイナリ変換して利用するのがベストプラクティスとなります。
※たぶんパフォーマンス面以外にもメリットはあると思うけど、調査しきれないので割愛。

参考サイト
https://dev.mysql.com/doc/refman/8.0/ja/miscellaneous-functions.html#function_uuid-to-bin
https://dev.mysql.com/doc/refman/8.0/ja/binary-varbinary.html
https://zenn.dev/reiwatravel/articles/9ce1050bf8509b
https://hiramekun.hatenablog.com/entry/2022/12/11/205710