PostgreSQL 的 id 完全可以使用全局唯一的值,而且有多种成熟方案可选。关键是理解"全局唯一"的级别:表级唯一 vs 库级唯一 vs 分布式系统全局唯一。
一、PostgreSQL 默认 ID 的局限性
sql
复制
-- 这些只是表级自增,无法保证全局唯一
id SERIAL PRIMARY KEY
id BIGSERIAL PRIMARY KEY
id INTEGER GENERATED ALWAYS AS IDENTITY
问题:
-
跨表可能重复(表A的id=1,表B的id=1)
-
分布式环境下不同数据库实例会生成相同ID
-
数据合并时会产生冲突
二、实现真正全局唯一的方案
方案1:UUID (最推荐)
sql
复制
-- 字段类型
id UUID PRIMARY KEY DEFAULT gen_random_uuid()
-- 需要启用扩展(PostgreSQL 13+ 内置)
CREATE EXTENSION IF NOT EXISTS pgcrypto;
优点:
-
✅ 真·全球唯一(跨表、跨库、跨服务器)
-
✅ 无需协调中心,本地生成
-
✅ 支持离线/分布式场景
-
✅ 安全,不易被猜测
缺点:
-
❌ 占用16字节(比INT的4字节大)
-
❌ 索引效率略低(但对现代硬件影响很小)
-
❌ 人类不可读
适用:微服务、多租户、数据仓库、事件溯源
方案2:Snowflake ID (Twitter 算法)
生成64位整数(如 1234567890123456789),结构:
| 1位符号 | 41位时间戳 | 10位机器ID | 12位序列号 |
实现方式:
-
使用自定义函数生成
-
使用外部ID生成服务(如美团 Leaf、百度 UID-Generator)
优点:
-
✅ 全局唯一
-
✅ 趋势递增(对索引友好)
-
✅ 占用8字节(BIGINT)
-
✅ 包含时间信息
缺点:
-
❌ 需要部署独立服务或配置机器ID
-
❌ 依赖系统时钟(时钟回拨会出问题)
适用:高并发、需要排序、性能敏感场景
方案3:组合键(业务语义ID)
sql
复制
-- 例如:订单ID = 时间 + 业务线 + 随机数
id VARCHAR(32) PRIMARY KEY DEFAULT generate_order_id()
生成逻辑:
sql
复制
-- 示例:20231115 + 账号后6位 + 随机数
20231115876543001234
优点:
-
✅ 包含业务信息,可读性强
-
✅ 全局唯一
缺点:
-
❌ 需要手写生成逻辑
-
❌ 长度不固定
-
❌ 可能泄露业务信息
适用:需要ID自解释的业务场景
方案4:全局序列序列 (Sequence)
sql
复制
-- 创建一个库级共享序列
CREATE GLOBAL SEQUENCE global_id_seq;
-- 所有表都用这个序列
id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq');
优点:
-
✅ 保证库级唯一
-
✅ 整数类型,性能最好
缺点:
-
❌ 只在单库有效,多库仍重复
-
❌ 有单点性能瓶颈
-
❌ 需要管理权限
适用:单体应用、无分库场景
三、方案对比总结
表格
复制
| 特性 | UUID | Snowflake | 组合键 | 全局序列 |
|---|---|---|---|---|
| 全局唯一性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 性能 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 可读性 | ⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 分布式支持 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ |
| 依赖 | 无 | 时钟/服务 | 业务逻辑 | 数据库 |
| 存储空间 | 16字节 | 8字节 | 变长 | 8字节 |
四、选型建议
-
90%场景:直接用
UUID,简单可靠,未来-proof -
超高并发+排序需求:用
Snowflake风格的 ID -
遗留系统改造:用
全局序列过渡 -
特殊业务:用
组合键(如订单号)
现代应用黄金法则:微服务架构下,无脑选 UUID,额外的存储成本远低于解决ID冲突的复杂度。
五、UUID 性能优化技巧
sql
复制
-- 1. 使用 UUID v7(时间有序,PostgreSQL 17+ 支持)
id UUID PRIMARY KEY DEFAULT gen_random_uuid_v7()
-- 2. 如果必须用UUID v4,可以创建索引时排序
CREATE INDEX idx_words_id ON words (id ASC);
PostgreSQL 15+ 对 UUID 索引已做了大量优化,性能差距已缩小到可忽略范围。
462

被折叠的 条评论
为什么被折叠?



