主键与自增
→ 返回 MySQL
InnoDB 按主键组织聚簇索引(B+ 树叶子存完整行),主键影响插入性能、二级索引体积与 JOIN。
原则
| 原则 | 说明 |
|---|---|
| 必须有主键 | 否则隐藏 DB_ROW_ID(不推荐依赖) |
| 尽量短 | 二级索引叶存主键副本 |
| 尽量稳定 | 主键变更 ≈ 删行 + 插行 |
| 代理键 | 能用 BIGINT 自增就别用易变业务字段 |
方案对比
| 方案 | 优点 | 缺点 | 适用 |
|---|---|---|---|
| BIGINT 自增 | 顺序插入、页分裂少 | 分库需段号 | 单库 OLTP |
| 雪花 / 号段 | 全局唯一、趋势递增 | 时钟回拨 | 分库分表 |
| UUID 随机 | 全局唯一 | 页分裂、索引膨胀 | 少量预生成 |
| UUID 有序 | UUIDv7 等 | 需 8.0+ 或应用生成 | 全局唯一 + 写入友好 |
| 业务自然键 | 语义清晰 | 变更成本高 | 码表、维度表 |
CREATE TABLE orders (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
order_no VARCHAR(32) NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
amount DECIMAL(12,2) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_order_no (order_no),
KEY idx_user_created (user_id, created_at)
) ENGINE=InnoDB;复合主键
(tenant_id, id) 常见于 SaaS:二级索引都带租户前缀;多数场景 单列自增主键 + 租户普通索引 更简单。
AUTO_INCREMENT
- 计数器在内存;重启/恢复注意号段
INSERT失败也消耗号段(空洞正常)LAST_INSERT_ID()当前会话最后自增值
SELECT AUTO_INCREMENT FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'app' AND TABLE_NAME = 'orders';为何自增友好
顺序插入落在最大叶页,少页分裂;随机 UUID 在中间插入 → 分裂与碎片。
分库分表发号
| 方案 | 思路 |
|---|---|
| 号段 | DB/Redis 批量取 [start,end] |
| 雪花 | 时间戳 + 机器 + 序列 |
| 步长+偏移 | id = n * 步长 + 库号 |
见 分布式 ID。