一、MySQL序列概述
为了达到标识的目的,许多应用程序需要生成唯一编号,比如:商品编号、交易流水号等。MySQL数据库同样能够支持这样的需求场景,AUTO_INCREMENT就是为MySQL实现序列的方式,它会自动生成序列编号。但是它的使用是有要求的,比如:
- 每个表只能有一个列具备AUTO_INCREMENT属性,并且为整数型
- AUTO_INCREMENT列不能包含NULL值(MySQL会自动设置为NOT NULL)
- AUTO_INCREMENT列上必选要有索引,常见为primary key和unique index
备注:由于存储引擎的不同对于序列的定义和使用存在差异,本文以innodb引擎作为讲解,具体差异区别,可参考后期分享:《浅析MySQL存储引擎序列属性》
二、场景演示
设置为AUTO_INCREMENT属性后,每一次插入数据都会向前增加一位数,但是如果删除行后,序列会怎么样呢?
mysql> CREATE TABLE animals ( -> id MEDIUMINT NOT NULL AUTO_INCREMENT, -> name CHAR(30) NOT NULL, -> PRIMARY KEY (id) -> ); Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO animals (name) VALUES -> ('dog'),('cat'),('penguin'), -> ('lax'),('whale'),('ostrich'); Query OK, 6 rows affected (0.01 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM animals; +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec)
复制
对于动物编号来说,序列的作用确实很好用,但是当删除某行数据后,序列会发生什么情况呢?
Query OK, 3 rows affected (0.02 sec) mysql> SELECT * FROM animals; +----+---------+ | id | name | +----+---------+ | 1 | dog | | 3 | penguin | | 5 | whale | +----+---------+ 3 rows in set (0.00 sec)
复制
现在序列(id)发生了断层
Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM animals; +----+---------+ | id | name | +----+---------+ | 1 | dog | | 3 | penguin | | 5 | whale | | 7 | Horse | +----+---------+ 4 rows in set (0.00 sec) mysql> INSERT INTO animals (name) VALUES ('Kangaroo'); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM animals; +----+----------+ | id | name | +----+----------+ | 1 | dog | | 3 | penguin | | 5 | whale | | 7 | Horse | | 8 | Kangaroo | +----+----------+ 5 rows in set (0.00 sec)
复制
在插入新数据后,原来被删除的序列已经不再重复使用了,而下一个序列为未使用的最小整数。删除当前行对于下一次序列的分配,没有影响。
对于每次数据进行插入,都会从AUTO_INCREMENT列中获取最大值,在进行偏移量增加。如默认的偏移量为1.
+--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1 | +--------------------------+-------+ 1 row in set (0.02 sec) mysql> show variables like 'auto_increment_offset'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | auto_increment_offset | 1 | +-----------------------+-------+ 1 row in set (0.00 sec)
复制
说明:对于最大值获取,不是简单使用max函数,这样并不准确,因为在并行事务中,可能会有其他会话进行插入更改,因此当前会话max值并不是准确的,同时还会存在自增长字段的值之间发生冲突,所以MySQL会调用LAST_INSERT_ID(),返回最新AUTO_INCREMENT最大值。
Query OK, 1 row affected (0.00 sec) mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 9 | +------------------+ 1 row in set (0.00 sec) mysql> INSERT INTO animals (name) VALUES ('DEFG'); Query OK, 1 row affected (0.01 sec) mysql> select * from animals where id =last_insert_id(); +----+------+ | id | name | +----+------+ | 10 | DEFG | +----+------+ 1 row in set (0.00 sec)
复制
对于并行事务,AUTO_INCREMENT 计数会怎么分配呢?
下面做个案例测试:
会话1:
mysql> set autocommit=0 -> ; Query OK, 0 rows affected (0.00 sec) mysql> select * from animals; +----+----------+ | id | name | +----+----------+ | 1 | dog | | 3 | penguin | | 5 | whale | | 7 | Horse | | 8 | Kangaroo | | 9 | ABC | | 10 | DEFG | +----+----------+ 7 rows in set (0.00 sec) mysql> INSERT INTO animals (name) VALUES ('LISAT1'); Query OK, 1 row affected (0.00 sec) mysql> select * from animals; +----+----------+ | id | name | +----+----------+ | 1 | dog | | 3 | penguin | | 5 | whale | | 7 | Horse | | 8 | Kangaroo | | 9 | ABC | | 10 | DEFG | | 11 | LISAT1 | +----+----------+ 8 rows in set (0.01 sec)
复制
会话2:
mysql> set autocommit=0 -> ; Query OK, 0 rows affected (0.00 sec) mysql> select * from animals; +----+----------+ | id | name | +----+----------+ | 1 | dog | | 3 | penguin | | 5 | whale | | 7 | Horse | | 8 | Kangaroo | | 9 | ABC | | 10 | DEFG | +----+----------+ 7 rows in set (0.00 sec) mysql> INSERT INTO animals (name) VALUES ('LISAT2'); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO animals (name) VALUES ('LISAT3'); Query OK, 1 row affected (0.00 sec) mysql> mysql> select * from animals; +----+----------+ | id | name | +----+----------+ | 1 | dog | | 3 | penguin | | 5 | whale | | 7 | Horse | | 8 | Kangaroo | | 9 | ABC | | 10 | DEFG | | 12 | LISAT2 | | 13 | LISAT3 | +----+----------+ 9 rows in set (0.00 sec)
复制
会话1:
mysql> rollback; Query OK, 0 rows affected (0.00 sec)
复制
会话2:
mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from animals; +----+----------+ | id | name | +----+----------+ | 1 | dog | | 3 | penguin | | 5 | whale | | 7 | Horse | | 8 | Kangaroo | | 9 | ABC | | 10 | DEFG | | 12 | LISAT2 | | 13 | LISAT3 | +----+----------+ 9 rows in set (0.00 sec)
复制
可以从上面的测试看出,当会话1持有该序列后,会对该序列占有语句锁,会话2重新申请下一个序列,因此出现了序列不连续情况,这样的目的其实也是为了避免线程冲突,性能优先。
在高效使用AUTO_INCREMENT列时,有几项注意事项:
- 自增序列的目的是得到一系列的正整数序列,,因此不支持非正数使用。
- 可以将AUTO_INCREMENT列定义为UNSIGED类型,创建主键 UNSIGNED 和 AUTO_INCREMENT 连用 表示从0开始自增 (由0开始自增,所以第一个自增的id为 1 ) 但可以增加的范围为,不加 UNSIGNED 的两倍
- 使用truncate table来清除某个表的内容,可以将该表的序列重置为1开始。
最后修改时间:2020-08-24 10:43:48
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
👍
1年前

评论
相关阅读
【MySQL 30周年庆】MySQL 8.0 OCP考试限时免费!教你免费领考券
墨天轮小教习
3258次阅读
2025-04-25 18:53:11
MySQL 30 周年庆!MySQL 8.4 认证免费考!这次是认真的。。。
严少安
903次阅读
2025-04-25 15:30:58
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
531次阅读
2025-04-17 17:02:24
MySQL 9.3 正式 GA,我却大失所望,新特性亮点与隐忧并存?
JiekeXu
456次阅读
2025-04-15 23:49:58
3月“墨力原创作者计划”获奖名单公布
墨天轮编辑部
382次阅读
2025-04-15 14:48:05
MySQL 8.0 OCP 1Z0-908 考试解析指南(二)
JiekeXu
348次阅读
2025-04-30 17:37:37
记录MySQL数据库的一些奇怪的迁移需求!
陈举超
302次阅读
2025-04-15 15:27:53
SQL优化 - explain查看SQL执行计划(下)
金同学
295次阅读
2025-05-06 14:40:00
MySQL 30 周年庆!MySQL 8.4 认证免费考!这次是认真的。。。
数据库运维之道
288次阅读
2025-04-28 11:01:25
MySQL 8.0 OCP 1Z0-908 考试题解析指南
青年数据库学习互助会
285次阅读
2025-04-30 12:17:54
TA的专栏
2020中国数据库技术大会PPT分享(DTCC 2020)
收录78篇内容
openGauss Meetup 资源分享
收录6篇内容
中国MySQL用户组(ACMUG)| 2020技术年会
收录9篇内容
目录