【MySQL】 SQL 执行顺序 OR 递增id用完了怎么办呢?哪个问题难回答

写在前面

三月已经结束了,不知道这个月你有没有被邀请面试,如果有面试的过程中有没有被问到MySQL的执行顺序是怎样的啊,如果MySQL中递增id用完了怎么处理的呢?先自己思考一下会不会跟面试官回答清楚,如果会的话,给自己点个赞,总结一下。
也可继续看这篇文章加深一下印象,评论区分享下自己的心得。

基础概念

在说这个 SQL 的执行顺序之前,还有几个知识点需要提一下。
笛卡尔积:两个集合相乘,得到的结果包含了两个集合中元素之和。

永久表:普通意义上自行创建的表,用于长期保存数据等操作。

临时表:分为两种,其一是为了保存数据,也可以长期存在于数据库中;其二是因为 SQL 执行中临时创建的,在 SQL 执行结束后,就会被删除。

虚表:虚表类似于一个结果集,也可以说成是一个视图,只是个执行结果。

SQL 执行顺序

假设一条查询语句是这样的:

select  返回的字段   from 表和关联表  where  查询条件

FROM

首先解析 From 两边的表,进行笛卡尔积的计算,产生一个虚表 table1。

ON

接着通过 ON 条件来进行筛选,形成第二个虚表 table2,最新的数据也在这里面。

JOIN

根据内连接和外连接的不同,这里也会有所不同,内连接会增加外部行,左连接会将 ON 过滤条件的左表添加进去,右连接会将 ON 过滤条件的右表添加进去,生成虚表 table3。

WHERE

接着就是执行 where 过滤,通过 where 条件的过滤形成虚表 table4。

GROUP BY

如果 SQL 语句中存在 group by,则会对虚表 table4 进行分组,产生出虚表 table5,紧接着会执行聚合函数。

HAVING

Group by 执行完毕,会继续执行 having 过滤,从而生成虚表 table6

SELECT

执行完上述语句后,就会执行 select 语句了,将虚表 table6 中的列,针对 select 进行筛选,随后生成出虚表 table7

DISTINCT

select 语句执行完毕后,就会去执行去重操作了,这里同样会生成新的虚表 table8

ORDER BY

执行完上述操作后,就该执行排序了,在排序之后还会执行 limit 操作。

到这里就是MySQL中常见的sql执行顺序了,你学会了不?

Mysql 自增 ID用完了

Mysql 自增 ID 上限的问题,可以分为两个方面来说。

1.有主键的情况

如果设置了主键,并且一般会把主键设置成自增,Mysql 里 int 类型是 4 个字节,如果有符号位的话就是[-231,231-1],无符号位的话最大值就是 2^32-1,也就是 4294967295。

创建一张表试试:

	CREATETABLE`test`(
	`id`int(11)NOTNULLAUTO_INCREMENT,
	`name`varchar(32)NOTNULLDEFAULT'',
	PRIMARYKEY(`id`)
	)ENGINE=InnoDBAUTO_INCREMENT=2147483647DEFAULTCHARSET=utf8mb4;

然后执行插入

insertintotest1(name)values('qq');

这样表里就有一条达到有符号位的最大值上限的数据。

如果再次执行插入语句:

insertintotest(name)values('ww');

就会看到错误提示:

1062 - Duplicate entry ‘2147483647’ for key ‘PRIMARY’, Time: 0.000000s。

也就是说,如果设置了主键并且自增的话,达到自增主键上限就会报错重复的主键 key。

解决方案

mysql 主键改为 bigint,也就是 8 个字节。
设计的时候要考虑清楚值的上限是多少,如果业务频繁插入的话,21 亿的数字其实还是有可能达到的。

2.没有主键

如果没有设置主键的话,InnoDB 则会自动帮你创建一个 6 个字节的 row_id,由于 row_id 是无符号的,所以最大长度是 2^48-1。

同样创建一张表作为测试:

CREATETABLE`test2`(
`name`varchar(32)NOTNULLDEFAULT''
)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

通过ps -ef|grep mysql拿到 mysql 的进程 ID,然后执行命令,通过 gdb 先把 row_id 修改为 1

sudogdb-p2584-ex'pdict_sys->row_id=1'-batch

然后插入几条数据:

insertintotest2(name)values('1');
insertintotest2(name)values('2');
insertintotest2(name)values('3');

再次修改 row_id 为 2^48,也就是 281474976710656

sudogdb-p2584-ex’pdict_sys->row_id=281474976710656’-batch
再次插入数据

insertintotest2(name)values('4');
insertintotest2(name)values('5');
insertintotest2(name)values('6');

然后查询数据会发现 3 条数据是 4,5,6,3。

因为我们先设置 row_id=1 开始,所以 1,2,3 的 row_id 也是 1,2,3。

修改 row_id 为上限值之后,row_id 会从 0 重新开始计算,所以 4,5,6 的 row_id 就是 0,1,2。

由于 1,2 数据已经存在,数据则是会被覆盖。

自增 ID 达到上限用完了之后,分为两种情况:

如果设置了主键,那么将会报错主键冲突。
如果没有设置主键,数据库则会帮我们自动生成一个全局的 row_id,新数据会覆盖老数据

解决方案:

表尽可能都要设置主键,主键尽量使用 bigint 类型,21 亿的上限还是有可能达到的,比如魔兽,虽然说 row_id 上限高达 281 万亿,但是覆盖数据显然是不可接受的。

总结

不管在任何时候出去面试的时候遇到问题都不要慌,要有信心,要相信自己可以取得offer的。
四月加油,期待可以点个免费的三连和关注哦。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/leng_yong/article/details/129916016