出自:
<姜承尧的MySQL实战宝典 >,本人学习完了在原文又做了一些更改和总结
在真实业务场景中,整型类型最常见的就是在业务中用来表示某件物品的数量。例如上述表的销售数量,或电商中的库存数量、购买次数等。在业务中,整型类型的另一个常见且重要的使用用法是作为表的主键,即用来唯一标识一行数据。
注意点1,用BITINT做主键,而不是INT
整型结合属性 auto_increment,可以实现自增功能,但在表结构设计时用自增做主键,希望你特别要注意以下两点,若不注意,可能会对业务造成灾难性的打击:
- 用 BIGINT 做主键,而不是 INT;
- 自增值并不持久化,可能会有回溯现象(MySQL 8.0 版本前)。
从表 1 可以发现,INT 的范围最大在 42 亿的级别,在真实的互联网业务场景的应用中,很容易达到最大值。例如一些流水表、日志表,每天 1000W 数据量,420 天后,INT 类型的上限即可达到。
因此,用自增整型做主键,一律使用 BIGINT,而不是 INT。不要为了节省 4 个字节使用 INT,当达到上限时,再进行表结构的变更,将是巨大的负担与痛苦。
那这里又引申出一个有意思的问题:如果达到了 INT 类型的上限,数据库的表现又将如何呢?是会重新变为 1?我们可以通过下面的 SQL 语句验证一下:
创建表
CREATE TABLE t
(
a INT AUTO_INCREMENT PRIMARY KEY
);
插入int的上限
INSERT INTO t
VALUES (2147483647);
此时t表里面的数据
a |
2147483647 |
再次插入
INSERT INTO t
VALUES (NULL);
可以看到,当达到 INT 上限后,再次进行自增插入时,会报重复错误,MySQL 数据库并不会自动将其重置为 1。
此时会报错,因为超过了int最大的范围, int范围是 -2147483648 ~2147483647
报错信息:
ERROR 1062 (23000): Duplicate entry ‘2147483647’ for key ‘t.PRIMARY’
注意点2.自增可能会存在回溯问题
第二个特别要注意的问题是,MySQL 8.0 版本前,自增不持久化,自增值可能会存在回溯问题!
CREATE TABLE t
(
a INT AUTO_INCREMENT PRIMARY KEY
);
INSERT INTO t (a)
VALUES (NULL),
(NULL),
(NULL);
SELECT *
FROM t;
此时表里面的数据是
a |
1 |
2 |
3 |
删除a为3的数据
DELETE
FROM t
WHERE a = 3;
查看建表语句
SHOW CREATE TABLE
此时内容:
Table | Create Table |
t | CREATE TABLE |
a
int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (a
)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 |
重点观察上面的AUTO_INCREMENT为4
此时我操作docker重启mysql,mysql版本是5版本
[root@zjj101 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b12e373a64e9 rabbitmq:management "docker-entrypoint.s…" 7 weeks ago Exited (255) 4 weeks ago 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, :::5672->5672/tcp, 15671/tcp, 15691-15692/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp, :::15672->15672/tcp rabbit
7d207bd13d18 87eca374c0ed "docker-entrypoint.s…" 7 weeks ago Up 46 hours 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql-service
[root@zjj101 ~]# docker restart 7d207bd13d18
重新执行sql查看建表语句
SHOW CREATE TABLE
Table | Create Table |
t | CREATE TABLE |
a
int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (a
)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 |
重启mysql之后重点观察上面的AUTO_INCREMENT从4变成3了
可以看到,在删除自增为 3 的这条记录后,下一个自增值依然为 4(AUTO_INCREMENT=4),这里并没有错误,自增并不会进行回溯。但若这时数据库发生重启,那数据库启动后,表 t 的自增起始值将再次变为 3,即自增值发生回溯。
若要彻底解决这个问题,有以下 2 种方法:
- 升级 MySQL 版本到 8.0 版本,每张表的自增值会持久化;
- 若无法升级数据库版本,则强烈不推荐在核心业务表中使用自增数据类型做主键。
其实,在海量互联网架构设计过程中,为了之后更好的分布式架构扩展性,不建议使用整型类型做主键,更为推荐的是字符串类型