说说 MySQL 自增字段取值

34次阅读

共计 2887 个字符,预计需要花费 8 分钟才能阅读完成。

1 前言
本文来自回答思否网友的一个问题,这个网友新建了一张表,auto_increment_increment 设为 10,AUTO_INCREMENT 主键起始值设为 9, 当他插入数据的时候,发现主键值是从 11 开始的,所以产生了疑惑。这篇文章一起来讨论一下自增字段问题。
2 自增字段计算方式
自增字段取值和 auto_increment_increment 参数和 auto_increment_offset 参数有关,auto_increment_offset 参数设置的是自增字段偏移值,也就是计算起始值,auto_increment_increment 参数设置的是自增字段的步长,也就是每次增加多少。auto_increment_increment 和 auto_increment_offset 经常用在主主复制中防止主键重复。auto_increment_increment 为 Integer 类型,取值 1 -65535,如果设置为 0, 会改为 1,如果设置超过取值范围,会改为 65535。
自增字段的取值是通过 auto_increment_offset + N × auto_increment_increment 这个公式计算出来的,而 N 是一个类似于 [1,2,3,…] 这样的递增序列。当插入一条数据时,数据库会从 auto_increment_offset + N × auto_increment_increment 计算出来的递增数列中取大于等于当前 AUTO_INCREMENT 的最小一个元素作为该字段下一个自增的值。
auto_increment_increment 可以动态改变,但是计算自增字段取值的时候,不会受已经存在的数据影响,计算方式不变。
下面让我们做一些测试
db83-3306>>SET @@auto_increment_increment=10;
Query OK, 0 rows affected (0.00 sec)

db83-3306>>SHOW VARIABLES LIKE ‘auto_inc%’;
+————————–+——-+
| Variable_name | Value |
+————————–+——-+
| auto_increment_increment | 10 |
| auto_increment_offset | 1 |
+————————–+——-+
2 rows in set (0.00 sec)

db83-3306>>CREATE TABLE autoinc1(
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
-> ) engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

db83-3306>>INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

db83-3306>>select * from autoinc1;
+—-+
| id |
+—-+
| 1 |
| 11 |
| 21 |
| 31 |
+—-+
4 rows in set (0.00 sec)
我们先创建了一个包含自增字段的表,把步长设为 10, 插入数据发现增长确实是公式中计算的值。下面我们再测试一下建表时设置 AUTO_INCREMENT 是否会有影响
db83-3306>>CREATE TABLE autoinc2(
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
-> ) engine=InnoDB AUTO_INCREMENT=8;
Query OK, 0 rows affected (0.01 sec)

db83-3306>>INSERT INTO autoinc2 VALUES (NULL), (NULL), (NULL), (NULL);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

db83-3306>>select * from autoinc2;
+—-+
| id |
+—-+
| 11 |
| 21 |
| 31 |
| 41 |
+—-+
4 rows in set (0.00 sec)
可以看到即使设置了 AUTO_INCREMENT 的值,也不影响自增字段的计算
3 其他情况
上面那是正常情况下的取值,下面我们探讨一种特殊情况
3.1 根据分组自增长
有一种特殊情况会造成自增长字段可能不会自增长, 就是当使用 MyISAM 引擎,且使用了联合索引,自增字段为非联合索引首个字段。
这种情况下,自增字段取值为 MAX(auto_increment_column) + auto_increment_offset WHERE prefix=given-prefix, 怎么理解,就是计算增长值的时候,对联合索引自增长字段前面字段做一个分组,在该分组内做一个独立的增长计算。
例如对 a,b,c 做了联合索引,c 是自增字段,那么对 where a=xx and b=xx 这个条件下的数据做独立的增长计算。下面是实例:
db83-3306>>CREATE TABLE user_pets (
-> name varchar(16) NOT NULL,
-> id_inc INT NOT NULL AUTO_INCREMENT,
-> pets varchar(16) NOT NULL,
-> PRIMARY KEY (name, id_inc)
-> ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.00 sec)

db83-3306>>INSERT INTO user_pets(name, pets) VALUES
-> (‘chengqm’, ‘dog’),
-> (‘chengqm’, ‘cat’),
-> (‘chengqm’, ‘fish’),
-> (‘yexm’, ‘dog’),
-> (‘yexm’, ‘cat’),
-> (‘yexm’, ‘fish’);
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0

db83-3306>>SELECT * FROM user_pets;
+———+——–+——+
| name | id_inc | pets |
+———+——–+——+
| chengqm | 1 | dog |
| chengqm | 11 | cat |
| chengqm | 21 | fish |
| yexm | 1 | dog |
| yexm | 11 | cat |
| yexm | 21 | fish |
+———+——–+——+
6 rows in set (0.00 sec)
从结果可以看出,在 name 字段相同的字段内,会有独立的自增长计算,这种计算方式在做 group by 的时候非常方便。

参考:

https://dev.mysql.com/doc/ref…
https://dev.mysql.com/doc/ref…

正文完
 0