UUIDをバイナリ(16バイト)で保存する
UUIDを36文字の文字列ではなく16バイトのバイナリで保存すべき理由と方法。55%のストレージ削減、インデックスパフォーマンス向上、メモリ使用量削減を実現します。
Concept
詳細な説明
UUIDは128ビットの値であり、本来16バイトに収まります。しかし多くのアプリケーションでは36文字の文字列表現で格納しており、ストレージの半分以上を無駄にしています。バイナリストレージへの変換により、データベースパフォーマンスを大幅に改善しコストを削減できます。
UUID1つあたりのストレージ比較:
| 形式 | サイズ | バイナリとの差分 |
|---|---|---|
| バイナリ(16バイト) | 16バイト | 基準値 |
| ハイフンなし16進数 | 32バイト | +100% |
| 標準文字列 | 36バイト | +125% |
| オーバーヘッド付き(VARCHAR) | 37-40バイト | +137-150% |
大規模環境での影響(1億行、UUIDカラム3つ):
| 形式 | UUID合計ストレージ | インデックスサイズ |
|---|---|---|
| BINARY(16) | 4.47 GB | 約3.5 GB |
| CHAR(36) | 10.05 GB | 約8.0 GB |
| 削減量 | 5.58 GB | 約4.5 GB |
MySQLでのバイナリストレージ:
-- Table definition
CREATE TABLE orders (
id BINARY(16) PRIMARY KEY,
customer_id BINARY(16) NOT NULL,
INDEX idx_customer (customer_id)
);
-- MySQL 8.0+ UUID conversion functions
INSERT INTO orders (id, customer_id)
VALUES (UUID_TO_BIN(UUID(), true), UUID_TO_BIN(@customer_uuid));
-- The 'true' parameter swaps time fields for UUID v1 ordering
-- For UUID v7, use: UUID_TO_BIN(UUID(), false) or just UUID_TO_BIN(UUID())
SELECT BIN_TO_UUID(id, true) as id FROM orders;
アプリケーション層での変換(JavaScript):
// UUID string to 16-byte Buffer
function uuidToBytes(uuid) {
const hex = uuid.replace(/-/g, '');
return Buffer.from(hex, 'hex');
}
// 16-byte Buffer to UUID string
function bytesToUuid(bytes) {
const hex = bytes.toString('hex');
return [
hex.slice(0, 8), hex.slice(8, 12), hex.slice(12, 16),
hex.slice(16, 20), hex.slice(20)
].join('-');
}
アプリケーション層での変換(Python):
import uuid
id = uuid.uuid4()
raw = id.bytes # 16 bytes
restored = uuid.UUID(bytes=raw)
assert id == restored
サイズ以上にバイナリストレージがパフォーマンスを改善する理由:
- インデックスの縮小: B-treeノードがページあたりより多くのキーを保持できるため、ルックアップあたりのディスク読み取りが減少します。16バイトのキーは36バイトのキーと比較して、ページあたり約2倍のエントリを格納できます。
- CPU比較速度: 16バイトの比較は36文字の比較よりも高速です。特にCPUが128ビットSIMD命令を使用できる場合に顕著です。
- メモリ効率: より小さいインデックスはバッファプール/ページキャッシュに収まりやすく、ディスクI/Oを削減します。
- ネットワーク転送: クエリ結果のバイナリUUIDは帯域幅の消費が少なく、大規模な結果セットでは重要です。
デバッグに関する懸念: バイナリUUIDはクエリ結果で人間が読めません。アプリケーション内に変換レイヤーを提供するか、デバッグ時にはデータベース関数(MySQLの BIN_TO_UUID、PostgreSQLの uuid 型では自動変換)を使用してください。
ユースケース
バイナリUUIDストレージは、キーあたり16バイトと36バイトの差がホットインデックスがInnoDBバッファプールに収まるかどうかに直接影響する高トラフィックMySQLアプリケーションにおいて、p99レベルのクエリレイテンシに影響を与えるため非常に重要です。