主键与自增

返回 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


相关