Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL8-SOP

  • MySQL实战45讲学习笔记

    • MySQL45讲学习笔记
    • MySQL基础架构
    • MySQL日志系统 (Redo Log 与 Binlog)
    • MySQL字符串字段索引优化
    • MySQL索引原理与优化
    • MySQL锁机制详解
    • MySQL事务与MVCC机制
    • MySQL普通索引与唯一索引的选择
    • MySQL优化器如何选择索引
    • MySQL抖动刷脏页
    • 表空间管理与回收
    • count函数详解
    • 日志索引
    • orderby工作原理
    • 随机排序实现
    • SQL性能差异函数与转换
    • 慢查询分析锁与版本
    • 幻读与间隙锁
    • 加锁规则分析
    • 应急性能优化方法
    • 数据持久化保证
    • 主备一致性原理
    • 高可用架构与切换
    • 备库延迟分析与优化
    • 主备切换GTID
    • 读写分离实践与问题
    • 数据库健康检查
    • 锁与死锁
    • 数据误删恢复
    • Kill命令详解
    • 查询与内存使用分析
    • Join原理与选择
    • 临时表原理与应用
    • 内部临时表详解
    • Memory引擎详解
    • 自增ID详解
      • 1. 自增ID基础概念
        • 1.1 自增ID的定义
        • 1.2 自增ID的特性
      • 2. 自增ID的类型与范围
        • 2.1 不同数据类型的自增范围
        • 2.2 自增ID的溢出处理
      • 3. 自增ID的工作机制
        • 3.1 自增值的分配策略
        • 3.2 自增值的存储位置
        • 3.3 自增值的持久化
      • 4. 自增ID的高级特性
        • 4.1 自增值的重置
        • 4.2 自增值的跳跃
        • 4.3 自增值的并发控制
      • 5. 自增ID的使用场景
        • 5.1 适合使用自增ID的场景
        • 5.2 不适合使用自增ID的场景
      • 6. 自增ID的性能优化
        • 6.1 自增值分配优化
        • 6.2 批量插入优化
        • 6.3 自增值预分配
      • 7. 自增ID的陷阱与注意事项
        • 7.1 删除数据后的自增值
        • 7.2 并发插入导致的性能问题
        • 7.3 自增值溢出风险
      • 8. 自增ID与其他主键方案对比
        • 8.1 自增ID vs UUID
        • 8.2 自增ID vs 雪花算法
        • 8.3 自增ID vs 复合主键
      • 9. 自增ID的最佳实践
        • 9.1 合理选择数据类型
        • 9.2 监控和预警机制
        • 9.3 定期维护策略
      • 10. 总结
    • Insert加锁分析
    • 表复制方法比较
    • Grant与权限管理
    • 分区表详解
    • SQL语句中的Join问题
    • 自增ID用尽问题
  • 专题系列
  • MySQL实战45讲学习笔记
Carry の Blog
2024-07-27
目录

自增ID详解

# 自增ID详解

自增ID(AUTO_INCREMENT)是MySQL中最常用和最重要的主键生成策略之一。它简单高效,但如果不合理使用,也可能带来严重问题。本文将深入探讨MySQL自增ID的各个方面。

# 1. 自增ID基础概念

# 1.1 自增ID的定义

自增ID是数据库表中一个特殊的数据列,当插入新记录时,如果没有显式指定该列的值,数据库会自动为其分配一个递增的唯一值。

-- 创建自增ID表
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

-- 插入数据
INSERT INTO users (name, email) VALUES 
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com');

-- 查看自增值
SELECT * FROM users;
-- 结果:
-- id | name  | email
-- 1  | Alice | alice@example.com
-- 2  | Bob   | bob@example.com
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 1.2 自增ID的特性

  1. 唯一性:每个自增ID值在表内唯一
  2. 连续性:默认情况下是连续递增的
  3. 自动性:插入时自动分配
  4. 单列性:通常作为主键使用

# 2. 自增ID的类型与范围

# 2.1 不同数据类型的自增范围

-- TINYINT UNSIGNED: 0 到 255
CREATE TABLE tinyint_table (
    id TINYINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(50)
);

-- SMALLINT UNSIGNED: 0 到 65,535
CREATE TABLE smallint_table (
    id SMALLINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(50)
);

-- MEDIUMINT UNSIGNED: 0 到 16,777,215
CREATE TABLE mediumint_table (
    id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(50)
);

-- INT UNSIGNED: 0 到 4,294,967,295
CREATE TABLE int_table (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(50)
);

-- BIGINT UNSIGNED: 0 到 18,446,744,073,709,551,615
CREATE TABLE bigint_table (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(50)
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 2.2 自增ID的溢出处理

-- 查看当前自增值
SHOW TABLE STATUS LIKE 'table_name';

-- 查看自增值使用情况
SELECT 
    AUTO_INCREMENT,
    CASE 
        WHEN COLUMN_TYPE LIKE '%UNSIGNED%' THEN POWER(2, LENGTH(COLUMN_TYPE) * 8) - 1
        ELSE POWER(2, LENGTH(COLUMN_TYPE) * 8 - 1) - 1
    END as max_value,
    ROUND((AUTO_INCREMENT / 
           CASE 
               WHEN COLUMN_TYPE LIKE '%UNSIGNED%' THEN POWER(2, LENGTH(COLUMN_TYPE) * 8) - 1
               ELSE POWER(2, LENGTH(COLUMN_TYPE) * 8 - 1) - 1
           END) * 100, 2) as usage_percentage
FROM information_schema.TABLES t
JOIN information_schema.COLUMNS c 
ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
WHERE t.TABLE_SCHEMA = 'your_database'
AND c.COLUMN_NAME = 'id'
AND c.EXTRA = 'auto_increment';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 3. 自增ID的工作机制

# 3.1 自增值的分配策略

-- 查看自增值分配策略
SHOW VARIABLES LIKE 'auto_increment_increment';
SHOW VARIABLES LIKE 'auto_increment_offset';

-- 自增值分配示例
-- 如果 auto_increment_increment = 1, auto_increment_offset = 1
-- 则自增值为:1, 2, 3, 4, 5...

-- 如果 auto_increment_increment = 2, auto_increment_offset = 1
-- 则自增值为:1, 3, 5, 7, 9...
1
2
3
4
5
6
7
8
9
10

# 3.2 自增值的存储位置

-- 查看自增值存储位置
SHOW CREATE TABLE users;

-- 自增值存储在表的元数据中,位于:
-- 1. 表的头信息中
-- 2. InnoDB存储引擎的系统表空间中
1
2
3
4
5
6

# 3.3 自增值的持久化

-- 自增值在以下情况会持久化:
-- 1. 数据库重启
-- 2. 表结构变更
-- 3. 手动设置自增值

-- 查看自增值持久化状态
SELECT 
    VARIABLE_NAME,
    VARIABLE_VALUE
FROM information_schema.GLOBAL_STATUS 
WHERE VARIABLE_NAME LIKE '%Auto_increment%';
1
2
3
4
5
6
7
8
9
10
11

# 4. 自增ID的高级特性

# 4.1 自增值的重置

-- 重置自增值
ALTER TABLE users AUTO_INCREMENT = 1;

-- 重置为特定值
ALTER TABLE users AUTO_INCREMENT = 1000;

-- 查看重置后的状态
SHOW TABLE STATUS LIKE 'users';
1
2
3
4
5
6
7
8

# 4.2 自增值的跳跃

-- 自增值跳跃的原因
-- 1. 事务回滚
-- 2. 插入失败
-- 3. 手动设置自增值
-- 4. 多线程并发插入

-- 示例:事务回滚导致跳跃
START TRANSACTION;
INSERT INTO users (name) VALUES ('Test1');
INSERT INTO users (name) VALUES ('Test2');
ROLLBACK;

-- 下次插入时,自增值可能跳过某些值
1
2
3
4
5
6
7
8
9
10
11
12
13

# 4.3 自增值的并发控制

-- 查看并发控制参数
SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';

-- 不同的锁模式:
-- 0: 传统锁模式(最安全但性能较差)
-- 1: 交替锁模式(默认,性能较好)
-- 2: 瞬时锁模式(最高性能)
1
2
3
4
5
6
7

# 5. 自增ID的使用场景

# 5.1 适合使用自增ID的场景

# 5.1.1 简单主键场景

-- 适合使用自增ID的场景
CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    order_date DATETIME,
    amount DECIMAL(10,2)
);

-- 优点:简单、高效、唯一
1
2
3
4
5
6
7
8
9

# 5.1.2 无业务含义的标识

-- 业务无关的标识符
CREATE TABLE logs (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    log_level VARCHAR(10),
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 适用于日志、审计等场景
1
2
3
4
5
6
7
8
9

# 5.2 不适合使用自增ID的场景

# 5.2.1 有业务含义的主键

-- 不适合使用自增ID的场景
CREATE TABLE employees (
    employee_code VARCHAR(20) PRIMARY KEY,  -- 业务编码
    name VARCHAR(50),
    department VARCHAR(50)
);

-- 员工编号有业务含义,不应使用自增ID
1
2
3
4
5
6
7
8

# 5.2.2 分布式系统

-- 分布式系统中应避免自增ID
-- 建议使用UUID或雪花算法ID
CREATE TABLE distributed_table (
    id CHAR(36) PRIMARY KEY DEFAULT (UUID()),  -- UUID
    data VARCHAR(100)
);

-- 或者使用雪花算法ID
CREATE TABLE distributed_table (
    id BIGINT UNSIGNED PRIMARY KEY,  -- 雪花算法ID
    data VARCHAR(100)
);
1
2
3
4
5
6
7
8
9
10
11
12

# 6. 自增ID的性能优化

# 6.1 自增值分配优化

-- 优化自增值分配
SET GLOBAL innodb_autoinc_lock_mode = 1;  -- 交替锁模式

-- 查看当前模式
SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';
1
2
3
4
5

# 6.2 批量插入优化

-- 批量插入优化
-- 不好的做法
INSERT INTO users (name) VALUES ('Alice');
INSERT INTO users (name) VALUES ('Bob');
INSERT INTO users (name) VALUES ('Charlie');

-- 好的做法 - 批量插入
INSERT INTO users (name) VALUES 
('Alice'),
('Bob'),
('Charlie');
1
2
3
4
5
6
7
8
9
10
11

# 6.3 自增值预分配

-- 预分配自增值(MySQL 8.0+)
-- 可以通过配置参数预分配
SET GLOBAL auto_increment_increment = 1;
SET GLOBAL auto_increment_offset = 1;
1
2
3
4

# 7. 自增ID的陷阱与注意事项

# 7.1 删除数据后的自增值

-- 删除数据后自增值不会重置
DELETE FROM users WHERE id > 1000;

-- 自增值仍然从某个值开始,可能很快用尽
-- 建议定期清理或重置
1
2
3
4
5

# 7.2 并发插入导致的性能问题

-- 高并发插入时的性能考虑
-- 可能出现锁竞争
-- 建议使用批量插入或异步插入
1
2
3

# 7.3 自增值溢出风险

-- 监控自增值使用情况
DELIMITER //
CREATE PROCEDURE check_auto_increment_usage()
BEGIN
    DECLARE usage_pct DECIMAL(5,2);
    DECLARE max_val BIGINT;
    DECLARE current_val BIGINT;
    
    SELECT 
        t.AUTO_INCREMENT,
        CASE 
            WHEN c.COLUMN_TYPE LIKE '%UNSIGNED%' THEN POWER(2, LENGTH(c.COLUMN_TYPE) * 8) - 1
            ELSE POWER(2, LENGTH(c.COLUMN_TYPE) * 8 - 1) - 1
        END,
        ROUND((t.AUTO_INCREMENT / 
               CASE 
                   WHEN c.COLUMN_TYPE LIKE '%UNSIGNED%' THEN POWER(2, LENGTH(c.COLUMN_TYPE) * 8) - 1
                   ELSE POWER(2, LENGTH(c.COLUMN_TYPE) * 8 - 1) - 1
               END) * 100, 2)
    INTO current_val, max_val, usage_pct
    FROM information_schema.TABLES t
    JOIN information_schema.COLUMNS c 
    ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
    WHERE t.TABLE_SCHEMA = 'your_database'
    AND c.COLUMN_NAME = 'id'
    AND c.EXTRA = 'auto_increment';
    
    -- 如果使用率超过80%,发出警告
    IF usage_pct > 80 THEN
        INSERT INTO alert_log (message, timestamp) 
        VALUES (CONCAT('Auto increment usage high: ', usage_pct, '%'), NOW());
    END IF;
END //
DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 8. 自增ID与其他主键方案对比

# 8.1 自增ID vs UUID

-- 自增ID
CREATE TABLE users_autoid (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50)
);

-- UUID
CREATE TABLE users_uuid (
    id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
    name VARCHAR(50)
);

-- 对比:
-- 自增ID:性能好,存储空间小,但不适用于分布式
-- UUID:分布式友好,但存储空间大,性能略差
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 8.2 自增ID vs 雪花算法

-- 雪花算法ID
CREATE TABLE users_snowflake (
    id BIGINT UNSIGNED PRIMARY KEY,
    name VARCHAR(50)
);

-- 雪花算法优势:
-- 1. 全局唯一
-- 2. 时间有序
-- 3. 分布式友好
-- 4. 无中心依赖
1
2
3
4
5
6
7
8
9
10
11

# 8.3 自增ID vs 复合主键

-- 自增ID
CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    order_date DATE
);

-- 复合主键
CREATE TABLE orders_compound (
    user_id INT,
    order_date DATE,
    order_number VARCHAR(50),
    PRIMARY KEY (user_id, order_date, order_number)
);

-- 对比:
-- 自增ID:简单、高效、适合大多数场景
-- 复合主键:适合业务逻辑明确的场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 9. 自增ID的最佳实践

# 9.1 合理选择数据类型

-- 根据业务规模选择合适的数据类型
-- 小型应用:INT
CREATE TABLE small_app (
    id INT AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(100)
);

-- 大型应用:BIGINT
CREATE TABLE large_app (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(100)
);
1
2
3
4
5
6
7
8
9
10
11
12

# 9.2 监控和预警机制

-- 创建自增值监控脚本
CREATE EVENT auto_increment_monitor
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
    DECLARE usage_pct DECIMAL(5,2);
    
    SELECT 
        ROUND((AUTO_INCREMENT / 
               CASE 
                   WHEN COLUMN_TYPE LIKE '%UNSIGNED%' THEN POWER(2, LENGTH(COLUMN_TYPE) * 8) - 1
                   ELSE POWER(2, LENGTH(COLUMN_TYPE) * 8 - 1) - 1
               END) * 100, 2)
    INTO usage_pct
    FROM information_schema.TABLES t
    JOIN information_schema.COLUMNS c 
    ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
    WHERE t.TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'performance_schema')
    AND c.COLUMN_NAME = 'id'
    AND c.EXTRA = 'auto_increment'
    AND t.TABLE_TYPE = 'BASE TABLE'
    AND t.AUTO_INCREMENT IS NOT NULL;
    
    -- 发出预警
    IF usage_pct > 80 THEN
        INSERT INTO alert_log (alert_type, message, timestamp) 
        VALUES ('AUTO_INCREMENT_HIGH_USAGE', 
                CONCAT('High auto increment usage: ', usage_pct, '%'), 
                NOW());
    END IF;
END;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 9.3 定期维护策略

-- 定期维护自增值
-- 1. 监控使用情况
-- 2. 预防性升级
-- 3. 数据清理

-- 定期检查脚本
DELIMITER //
CREATE PROCEDURE maintenance_auto_increment()
BEGIN
    -- 检查表状态
    SELECT 
        TABLE_SCHEMA,
        TABLE_NAME,
        AUTO_INCREMENT,
        CASE 
            WHEN COLUMN_TYPE LIKE '%UNSIGNED%' THEN POWER(2, LENGTH(COLUMN_TYPE) * 8) - 1
            ELSE POWER(2, LENGTH(COLUMN_TYPE) * 8 - 1) - 1
        END as max_value
    FROM information_schema.TABLES t
    JOIN information_schema.COLUMNS c 
    ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
    WHERE t.TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'performance_schema')
    AND c.COLUMN_NAME = 'id'
    AND c.EXTRA = 'auto_increment';
END //
DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 10. 总结

自增ID是MySQL中最实用的主键生成方式之一,它简单、高效、可靠。正确使用自增ID可以显著提升数据库性能和开发效率。

关键要点包括:

  1. 合理选择数据类型:根据业务规模选择合适的自增ID类型
  2. 监控使用情况:定期监控自增值使用率,预防溢出
  3. 避免滥用:在不适合的场景下避免使用自增ID
  4. 性能优化:通过合理的配置和使用方式优化性能
  5. 分布式考虑:在分布式系统中考虑使用其他ID生成方案

通过遵循这些最佳实践,可以充分发挥自增ID的优势,同时避免潜在的问题,为数据库系统的稳定运行奠定良好基础。

#MySQL#自增ID#主键设计#数据库优化#学习笔记
上次更新: 3/4/2026

← Memory引擎详解 Insert加锁分析→

最近更新
01
表空间管理与回收
03-04
02
MySQL抖动刷脏页
03-04
03
count函数详解
03-04
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式