CodeGym /コース /SQL SELF /ユニークIDの生成

ユニークIDの生成

SQL SELF
レベル 16, レッスン 0
使用可能

コンピュータがネットワークでガンガン繋がり始めたとき、シンプルだけど超重要な問題が出てきたんだ:どうやって、世界の全然違う場所にある2台のデバイスが、同じIDを作っちゃわないように保証する?

想像してみて:サーバーが2台、1台は東京、もう1台はベルリン。どっちも独立してオブジェクトのIDを作ってる。もし偶然同じIDを作っちゃったら、データがごっちゃになったり、上書きされたり、システムが落ちたりするかも。

そんなわけで、1990年代、分散システムやネットワークプロトコルが爆発的に発展してた時代、MicrosoftとOpen Software Foundation(OSF)の中でGUIDってアイデアが生まれたんだ。Globally Unique Identifier、つまりグローバルユニークIDってやつ。

GUID(ISO標準だとUUID、Universally Unique Identifier)は128ビットの数字で、例えばこんな感じ:

550e8400-e29b-41d4-a716-446655440000

これ、デジタルの指紋みたいなもんで、めっちゃ長くてランダムだから、IDがかぶる(コリジョン)確率はほぼゼロなんだ。

作り方は:

  • 時間
  • ランダムな数字
  • デバイスのMACアドレス(古いバージョンの場合)
  • あと暗号ハッシュ関数とか

なんでこれが大事だったかっていうと、GUIDがあれば中央サーバーも調整もなしでユニークIDが作れる。ロックも遅延もいらない。これが本当に助かったのは:

  • 分散データベース
  • ネットワークプロトコル
  • ドキュメント管理システム
  • もちろん今どきのAPI

PostgreSQLでのUUID

GUID/UUIDはどこでも使われてるよ。PostgreSQLからクラウドサービスまで。今のインターネットの裏方みたいな存在で、これがなかったら世界をこんな簡単に繋げなかった。

実際はめっちゃ長いランダムな数字(16バイト)で、16進数で書かれてる。ただのすごく長い整数だよ。

このデータ型は、システム全体で値のユニークさを保証したいときにピッタリ。ID生成サーバーに依存しなくていい。分散システムや、データがいろんなサーバーで作られるときに特に便利。

なんで単純にINTEGERじゃダメなの?

「UUIDなんていらなくない?IDは自動増分の数字でいいじゃん」って思うかも。ちょっと考えてみよう:

グローバルなユニーク性:もしDBが複数サーバーで動いてたら、INTEGERのユニーク性を保証するのは難しい。UUIDならこの問題は解決。

セキュリティとデータ隠し:UUIDは連番より予測しにくい。予測しやすいID(例:/users/1, /users/2)だと情報漏洩のリスクが上がるけど、UUIDなら安心。

分散システム:データがシステムのいろんな場所で作られるなら、自動増分INTEGERは同期が面倒。

もう一つのメリットは、UUIDは多くのプログラミング言語やストレージシステムで標準サポートされてること。

UUIDを使うメリット

主な良いところ:

  • ユニーク性:データが違うサーバーやシステムで作られてもIDのユニークさが保証される。
  • 柔軟性:主キー、外部キー、他の用途にも使える。
  • スケーラビリティ:分散DBで扱いやすい。

でもUUIDにもデメリットはある:

  • サイズ:UUIDはメモリでINTEGER(4バイト)より大きい(16バイト)。
  • 読みやすさ:数字より読みにくいし覚えにくい。

PostgreSQLでのUUID生成

組み込み関数gen_random_uuid()

PostgreSQL 13からは、gen_random_uuid()っていう組み込み関数でランダムなUUIDが作れる。この関数はユニークIDを返して、UUID型カラムの値に使えるよ。

例:

SELECT gen_random_uuid();

結果:

d17fc23b-22e5-4fcb-bf86-1b4c766d77b7

pgcrypto拡張が入ってるか確認しよう(PSQL 1-12用)

PostgreSQLの古いバージョン(13未満)だと、gen_random_uuid()はpgcrypto拡張を入れた後に使える。もし職場でこれを使えって言われたら、次のコマンドでなんとかなる:

CREATE EXTENSION IF NOT EXISTS "pgcrypto";

これでランダムなUUIDが生成できるようになる。

UUIDを外部キーとして使う

UUIDはテーブル同士のリレーションを作るのにも便利。例えばユーザーテーブルがあるとする:

id name email
d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 Alice alice@example.com
a1d3e15a-abc1-4b51-a320-2d4c859f7467 Bob bob@example.com
3c524998-5c24-4e73-836d-a4c6bb3cafcd Charlie charlie@example.com

ordersテーブルの作成

ordersテーブルを作って、user_idを外部キーにしてusersテーブルのidを参照するようにしよう。

order_id user_id order_date
1a5b7d9c-b1a2-4f8e-9e7a-0a1111111111 d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 2024-10-15 10:00:00
2b6c8e0d-c2b3-5a9f-af8b-1b2222222222 a1d3e15a-abc1-4b51-a320-2d4c859f7467 2024-10-15 10:05:00
3c7d9f1e-d3c4-6baf-bc9c-2c3333333333 3c524998-5c24-4e73-836d-a4c6bb3cafcd 2024-10-15 10:10:00
4d8eaf2f-e4d5-7cb0-cdab-3d4444444444 d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 2024-10-15 10:15:00
5e9fb030-f5e6-8dc1-debc-4e5555555555 a1d3e15a-abc1-4b51-a320-2d4c859f7467 2024-10-15 10:20:00

user_idカラムはusersテーブルのidと繋がってて、ユーザーと注文のリレーションが作れる。

JOINでデータ取得

usersとordersテーブルのデータがどう繋がってるか見てみよう:

SELECT 
    u.id AS user_id, 
    u.name, 
    o.order_id, 
    o.order_date 
FROM users u
JOIN orders o ON u.id = o.user_id;

結果:

user_id name order_id order_date
d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 Alice a1d3e15a-abc1-4b51-a320-2d4c859f7467 2024-10-20 12:34:56

UUIDの主な使いどころ

ユーザーや注文のID:分散システムで、データがいろんなソースから来る場合。

API用のマーカー:UUIDはREST APIでエンティティの識別子としてよく使われる。

グローバルなデータ同期:例えば、データが複数サーバーから集まるとき。

よくあるミスや注意点

UUIDを手動で作ろうとする:エラーを避けるために、gen_random_uuid()みたいな組み込み関数を使った方がいい。

使いすぎ:スケールしないローカルテーブルとか、単純な自動増分INTEGERで十分な場合はUUIDを使わなくてOK。

サイズ:UUIDはサイズが大きいから、特にインデックスを貼るときはクエリのパフォーマンスに影響することもある。

2
タスク
SQL SELF, レベル 16, レッスン 0
ロック未解除
UUIDの生成
UUIDの生成
2
タスク
SQL SELF, レベル 16, レッスン 0
ロック未解除
関連テーブルでのUUIDの紐付け
関連テーブルでのUUIDの紐付け
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION