Open2

MySQLでUUIDを使う場合

digarashi91digarashi91

idとして連番ではなくUUIDを採用したい場合のはなし

id発行

Postgres と MySQL における id, created_at, updated_at に関するベストプラクティス
MySQLでプライマリキーをUUIDにする前に知っておいて欲しいこと

これらの記事を読んで、パフォーマンス的に問題が発生しそうと思い、
以下の方法でidを発行することとした。

CREATE TABLE `samples` (
    id BINARY(16) NOT NULL DEFAULT (UUID_TO_BIN(UUID(), 1)),
    # ほかもろもろ

    PRIMARY KEY (id)
);

取得するとき

今回得たいidは以下の文字列。

e2e8e48c-df8c-11ed-b349-0242ac160002

このとき、単純にSELECTすると以下の結果となる。
(今回はプリペアドステートメントは使いません。)

// db接続処理

$sql = 'SELECT * FROM `samples`;';
$stmt = $pdo->query($sql);
$results = $stmt->fetchAll(PDO::FETCH_BOTH);

var_dump($results);
/**
array() {
  ["id"]=>
  string(16) "�ߌ��䌳IB�"
}
*/

いろいろ試した

SELECTする「*」の部分を色々置き換えてみたのと、PHP側でどのようにechoするか、その結果をまとめた図が以下。

SQLの*の部分 PHP 結果 一致
id echo �ߌ��䌳IB� ×
id echo bin2hex() 11eddf8ce2e8e48cb3490242ac160002 ×
HEX(id) echo hex2bin() 11eddf8ce2e8e48cb3490242ac160002 ×
BIN_TO_UUID(id, 0) echo 11eddf8c-e2e8-e48c-b349-0242ac160002 ×
BIN_TO_UUID(id, 1) echo e2e8e48c-df8c-11ed-b349-0242ac160002

一致したのが一番最後の行のみ。
発行するときに、UUID_TO_BIN()の第2引数に1を指定して時間部分のスワップをしているため、
取得するときもBIN_TO_UUID()の第2引数に1を指定しなければいけないっぽい。

疑問

カラム数が多いときとかも、いちいち全部指定しなきゃいけないのかな。
ほかの言語だとスワップした部分を戻したりできるのかな。
O/Rマッパーとかだとどうなるんだろ。

参考

https://dev.mysql.com/doc/refman/8.0/ja/miscellaneous-functions.html#function_uuid
https://zenn.dev/mpyw/articles/rdb-ids-and-timestamps-best-practices#id-(データ型と-insert-時のデフォルト埋め)
https://techblog.raccoon.ne.jp/archives/1627262796.html

digarashi91digarashi91

疑問

カラム数が多いときとかも、いちいち全部指定しなきゃいけないのかな。

全部指定するのがいいっぽい。

理由

  • インプリシットカラム(SQLアンチパターン)
  • パフォーマンスの問題?
  • テーブル定義が変わったときにわかりやすい