网站首页 > 技术文章 正文
哈喽,你好啊,我是雷工!
最近在研究数据库设计表格时,用到主键的设计。
由于没有系统的学习过相关知识,一时不知道该如何设计主键,
于是遇事不决问AI,决定通过问AI的形式学习一下该如何设计主键,并避免重复策略。
01 如何提问
问题如下:
设计数据库时主键该如何设计,用什么作为主键,而且如何避免重复?
02 解决方案
以下是AI给出的回答:
设计数据库主键是一个核心问题,直接影响数据完整性、查询性能、扩展性和维护性。以下是主键设计的核心原则、常见方案以及避免重复的策略:
一、主键的核心要求
- 唯一性:在整个表中绝对唯一,不能重复。
- 非空性:不能为 NULL。
- 稳定性:值一旦生成,最好永不改变(避免外键引用失效)。
- 简洁性:尽量短小(利于索引效率和外键存储)。
- 简单性:最好是单一字段(非强制,但复合主键会增加复杂度和外键引用难度)。
二、常见主键设计方案及优缺点
方案 | 优点 | 缺点 | 适用场景 |
1. 自增整数 (AUTO_INCREMENT / SERIAL) | 简单易用<br> 存储空间小<br> 索引效率高<br> 天然保证唯一性 | 无业务含义<br> 分库分表时需额外处理<br> 易暴露数据量<br> 插入前无法预知ID | 单机/简单系统、OLTP 核心表、不关心业务含义的场景 |
2. UUID/GUID | 全局唯一(跨库/跨服务器)<br> 生成无需依赖数据库<br> 隐藏数据量 | 存储空间大 (32字符)<br> 索引效率低(随机写入)<br> 无序性导致页分裂 | 分布式系统、需要提前生成ID、数据合并场景 |
3. 雪花算法 (Snowflake ID) | 全局唯一、大致有序<br> 存储空间适中 (64-bit)<br> 高性能 | 实现复杂(需维护机器ID)<br> 依赖系统时钟(时钟回拨问题) | 高并发分布式系统、需要全局有序ID的场景 |
4. 业务主键 (Natural Key) | 有业务含义<br> 可读性强<br> 可能减少关联查询 | 可能变更(违反稳定性)<br> 可能过长<br> 组合键复杂<br> 唯一性难保证 | 编码规则严格且不变的场景(如身份证号、ISBN) |
5. 混合方案 (业务键+代理键) | 平衡业务需求和稳定性 | 增加冗余字段<br> 设计稍复杂 | 既需业务标识又需稳定主键的场景 |
三、如何避免主键重复 - 关键策略
- 使用数据库自增机制:
- AUTO_INCREMENT (MySQL), SERIAL (PostgreSQL), IDENTITY (SQL Server), Sequence (Oracle, PostgreSQL)。
- 优点:数据库内部保证唯一性,绝对可靠。
- 缺点:仅适用于单库或主从复制环境,分布式环境下需特殊方案(如设置不同初始值/步长 - 不推荐)。
- 使用标准化全局唯一生成器:
- UUID/GUID:使用标准库生成(如 UUID.randomUUID())。理论上重复概率极低(2^128),可认为唯一。
- 雪花算法 (Snowflake):确保机器ID(workerId)在集群内唯一,解决时钟回拨问题(时钟回拨可能导致重复)。
- Redis 自增:利用 Redis 的原子操作 INCR 生成集群范围内唯一的序列号。
- 数据库 Sequence 服务:专门提供分布式 ID 生成服务(如 TDDL Sequence、Leaf)。
- 业务主键的严格校验:
- 数据库唯一约束:在业务字段上创建 UNIQUE 约束,作为最后防线。
- 应用层校验:插入/更新前检查该业务值是否存在(注意并发问题!需结合数据库唯一约束)。
- 预生成与分配:由中心系统按规则生成并分配业务主键值(如订单号生成服务)。
- 分布式数据库的特殊支持:
- NewSQL 数据库(如 TiDB、CockroachDB)提供 AUTO_RANDOM 或分布式序列机制。
四、关键设计原则与建议
- 优先选择代理键: 95% 的场景推荐使用 自增ID(单机)或 雪花ID/UUID(分布式)作为主键。它们稳定、简单、解耦业务。
- 避免使用业务主键: 除非该业务属性 绝对稳定、简短且唯一性可保证(如身份证号,但需注意隐私和变更情况)。
- 禁止使用可能变更的字段: 如用户名、邮箱、公司名称等。
- 避免大字段做主键: 如 TEXT, BLOB,严重影响索引性能。
- 复合主键谨慎使用: 增加复杂度,影响关联表设计。仅在多对多关系表或强业务约束下使用。
- 显式定义主键: 即使有唯一索引,也应显式定义 PRIMARY KEY,优化器会优先使用。
- 主键就是聚簇索引(多数DBMS): 主键顺序影响物理存储(InnoDB)。有序ID(自增、雪花)插入性能远高于随机ID(UUID)。
- UUID 优化:
- 使用 UUIDv7(时间戳有序)代替 v4(完全随机)。
- 存储时转换为 BINARY(16) 减少空间(如 MySQL 用 UNHEX(REPLACE(UUID(), '-', '')))。
五、示例选择指南
- 用户表 (user):id BIGINT AUTO_INCREMENT 或 id BIGINT(雪花ID)
- 绝对不要用 username 或 email 做主键!(可能变更,且较长)
- 订单表 (order):order_id VARCHAR(32)(包含日期+序列号的业务号,并额外加一个 id BIGINT AUTO_INCREMENT/雪花 作为主键)
- 业务号可做唯一索引,主键用代理键。
- 国家表 (country):country_code CHAR(2) PRIMARY KEY(ISO 3166-1 标准,稳定且短小)
- 用户-角色关联表 (user_role):(user_id, role_id) PRIMARY KEY(经典复合主键场景)
总结:最佳实践路径
- 默认选择: 单机/简单系统 → 自增整数 (AUTO_INCREMENT)。分布式系统 → 雪花算法 (Snowflake)。
- 特殊需求: 需要提前生成ID → UUIDv7。严格业务标识 → 业务键+代理键+唯一约束。
- 绝对底线:主键必须唯一、非空、稳定。无论选哪种方案,最终一定要在数据库层通过 PRIMARY KEY 约束来保证唯一性,这是最后的堡垒。
通过遵循这些原则,你就能设计出既高效又健壮的主键结构,为数据库的稳定性和扩展性打下坚实基础!
猜你喜欢
- 2025-09-01 分布式一致性算法--Paxos_分布式一致性
- 2025-09-01 基于DAO模式的Hibernate框架 在Java Web开发中的应用
- 2025-09-01 中小企业佳选正睿ZI1TS4-4536服务器评测
- 2025-09-01 navicat premium 注册码,各版本都有
- 2025-09-01 五家国内半导体标签管理软件服务商推荐及对比
- 2025-09-01 工控人必看!昆仑通态100个技术问题大揭秘,学完你就是高手!
- 2024-11-07 AWR基本操作 awr7
- 2024-11-07 ORA-19809: 超出了恢复文件数的限制故障处理实例
- 2024-11-07 Oracle Rman 不完全恢复实操讲解 oracle数据库不完全恢复
- 2024-11-07 Oracle 死锁与慢查询总结 oracle死锁产生原因
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- Oracle RAC (76)
- oracle恢复 (77)
- oracle 删除表 (52)
- oracle 用户名 (80)
- oracle 工具 (55)
- oracle 内存 (55)
- oracle 导出表 (62)
- oracle约束 (54)
- oracle 中文 (51)
- oracle链接 (54)
- oracle的函数 (58)
- oracle面试 (55)
- 前端调试 (52)
本文暂时没有评论,来添加一个吧(●'◡'●)