MySQL - UUID
MySQL - 使用 UUID 作为唯一标识符
Section titled “MySQL - 使用 UUID 作为唯一标识符”MySQL 的 UUID() 函数
Section titled “MySQL 的 UUID() 函数”MySQL 中的 UUID() 函数根据 RFC 4122(版本 1)生成通用唯一标识符(UUID)。这些值旨在跨所有服务器和所有时间都是唯一的。UUID 是通过当前时间戳、服务器唯一的 MAC 地址和随机数的组合生成的,这使得冲突的可能性极小。
理解 UUID 格式
Section titled “理解 UUID 格式”UUID() 函数返回一个 128 位数字,格式为 UTF-8 字符串,由五个十六进制段组成,并用连字符分隔。
标准格式为:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee。
生成 UUID
Section titled “生成 UUID”执行该函数很简单:
SELECT UUID();每次调用都会生成一个新且唯一的值。
| UUID() |
|---|
| 5c6f7b1e-7517-11ee-8a39-0242ac130003 |
UUID 作为主键:优点与缺点
Section titled “UUID 作为主键:优点与缺点”在分布式系统中使用 UUID 作为主键很常见,但也有一些权衡:
- 优点:
- 全球唯一性: 可以在不同的系统上生成记录而不会产生 ID 冲突,这对于微服务或离线数据同步非常理想。
- 安全性: 它们不暴露顺序信息。用户无法从
/users/123猜测出/users/124。 - 无状态生成: 应用程序可以生成自己的 ID,而无需查询数据库。
- 缺点:
- 存储大小: UUID 字符串(
VARCHAR(36))占用 36 字节,远超 4 字节的INT或 8 字节的BIGINT。 - 性能: UUID 不是顺序的。将新的随机值插入索引(尤其是 InnoDB 主键这样的聚簇索引)会导致页分裂和索引碎片化,从而导致写入和读取变慢。
- 可读性: 它们很难供人类阅读、记忆或比较。
- 存储大小: UUID 字符串(
最佳实践:将 UUID 存储为 BINARY(16)
Section titled “最佳实践:将 UUID 存储为 BINARY(16)”为了缓解存储和性能问题,现代最佳实践是将 UUID 存储在 BINARY(16) 列中。这直接存储 128 位值,只使用 16 字节。MySQL 8.0+ 提供了便捷的函数:UUID_TO_BIN() 用于将 UUID 字符串转换为二进制,BIN_TO_UUID() 用于将其转换回可显示的形式。
创建带 BINARY UUID 的表
Section titled “创建带 BINARY UUID 的表”在这里,我们创建一个 Logins 表,其中 id 是 BINARY(16) 主键。
CREATE TABLE Logins ( id BINARY(16) PRIMARY KEY, user_id INT NOT NULL, login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ip_address VARCHAR(45));插入和检索 UUID
Section titled “插入和检索 UUID”插入时,您必须将 UUID 字符串转换为二进制。选择时,将其转换回可读字符串。
-- 生成新的 UUID 并存储在变量中以提高清晰度SET @new_uuid = UUID();
-- 使用 UUID_TO_BIN() 插入记录INSERT INTO Logins(id, user_id, ip_address)VALUES (UUID_TO_BIN(@new_uuid), 101, '192.168.1.100');
-- 使用 BIN_TO_UUID() 检索记录SELECT BIN_TO_UUID(id) as login_id, user_id, login_timeFROM LoginsWHERE user_id = 101;输出显示了人类可读的 UUID:
| login_id | user_id | login_time |
|---|---|---|
| your-generated-uuid-here | 101 | 2023-10-27 10:30:00 |
已弃用的实践:将 UUID 存储为 VARCHAR
Section titled “已弃用的实践:将 UUID 存储为 VARCHAR”尽管简单,但将 UUID 存储在 VARCHAR(36) 列中效率极低。它使用的存储空间是两倍多,并且索引性能不佳。在新应用程序中应避免使用。
示例(仅供参考)
Section titled “示例(仅供参考)”-- 反模式:低效存储CREATE TABLE OldOrders ( order_id VARCHAR(36) PRIMARY KEY, product_name VARCHAR(100));
-- 插入是直接的,但性能会受影响INSERT INTO OldOrders (order_id, product_name)VALUES (UUID(), 'Legacy Keyboard');建议: 在现代 MySQL 数据库中,始终优先使用 BINARY(16) 来存储 UUID。对于需要兼顾性能和 UUID 优势的应用程序,可以考虑在应用程序层面实现时间排序的 UUID(例如 UUIDv7),以改善索引局部性。