Skip to content

MySQL面试题

约 2449 字大约 8 分钟

每日一问数据库

2025-11-04

MySQL的执行流程:连接器 --> 分析器 --> 优化器 --> 执行器 --> innodb存储引擎;

B+树作为索引结构原因:B+树的非叶子节点不存储完整的数据,只存储索引字段数据,叶子结点是两两互相连接的;

MySQL面试题

说一说MySQL的执行流程

连接器 --> 分析器 --> 优化器 --> 执行器 --> innodb存储引擎

查询数据到bufferpool --> 记录undolog日志 --> 更新bufferpool数据 --> redolog日志(prepare状态)--> binlog日志 --> redolog日志(commit状态)--> 刷盘(持久化)

mysql的执行流程可以分为两部分,一部分是Server层,一部分是存储引擎层。

Server层的流程是先到连接器验证访问权限,创建连接,然后到分析器里校验语法等关键字的正确性,再到优化器里主要选择合适的索引等操作,最后到执行器里调用存储引擎层。

存储引擎层,如果是innodb存储引擎,则是先将需要操作的数据所在数据页从idb磁盘文件里读取到BufferPool缓存池数据页里。

再记录更新操作到undolog日志里后,再更新BufferPool缓存池里的数据,再将日志记录到redolog日志里,并标记为prepare状态,然后再将整个事务的操作记录binlog日志,并刷盘,之后再将redolog日志里的prepare状态修改为commit状态(此为两阶段提交)。

最后系统会以数据页为单位将BufferPool里更新的数据写入磁盘,进行持久化。

详细介绍可查看《 MySQL架构的理解分析

MySQL为什么选择B+树作为索引结构

B+树的非叶子节点不存储完整的数据,只存储索引字段数据,叶子结点是两两互相连接的。

B树的特点是从上到下,从左到右是有序的。

相比于普通的二叉树结构,B树的一个节点可以存储多个元素。

每个节点的元素信息都是一条完整的数据记录,这就会导致当一条数据占用空间较大时,一个数据页能存储的数据就更少,整个树的层数会更多。

B+树同样是上到下,左到右是有序的,但是B+树的非叶子节点不存储完整的数据,只存储索引字段数据,完整的数据全部存放在叶子节点。

所以B+树只需要3层(一个数据页16KB,大概存1170条索引字段数据),就可以存储近2千万数据,查询时进行的磁盘IO操作更少,效率自然就比B树高出一大截。

非叶子节点中一个元素的左侧指针指向比自己小的元素所在子节点,右侧指针指向大于等于自己的元素所在子节点。

B+树的叶子结点是两两互相连接的,在进行范围遍历时效率更高,可以快速的遍历所有后续节点。

说说数据库索引的设计原则

  • 使用短索引,如果需要对一个长字符串字段列进行索引,应该只取其一定长度的前缀字符构成索引即可(一般情况下,前20个字符串可以过滤出大多数的数据结果),可以节省大量的索引空间,一个数据页存储的索引字段也就更多,磁盘IO的次数也就更少。

  • 不能创建过多的索引,在修改表内容时,是需要额外维护这些索引结构的,过多的索引,会导致总体的维护时间更长,也就降低了数据表写操作的性能。

  • 小基数字段不建议创建索引,例如性别,只有男女两种值,数据过滤的性能就不太好。除非是向逻辑删除字段,删除的数据占最大多数,只有一小部分是有效的数据,那这个字段就可以创建一个索引。

  • 可以建唯一索引的,尽量建成唯一索引。

  • 创建组合索引时,按照最左前缀原则,根据使用频率从左到右排列创建,因为MySQL在使用索引时,是从联合索引的最左列开始向右匹配的。使用联合索引还有个好处,当查询不符合最左前缀原则时,MySQL8的高版本还支持跳跃扫描,当第一个字段的基数不大时,会跳过第一个索引字段的比对,直接比对第二个字段,因为组合索引在第一个字段相同的情况下,第二个字段是有序的,这么扫描起来相对于全表扫描,效率也是相对较高的。

  • where与order by冲突时,优先满足where去走索引。

  • 代码先行,索引后上(等主体业务功能开发完毕之后再把涉及到的sql拿出来分析之后再设计创建对应的索引,这样创建的索引命中会更精准)

  • 可以持续关注MySQL的slow.log慢sql查询日志,针对这些慢sql查询做特定的索引优化

什么是聚集索引和非聚集索引

存完整数据的就是聚集索引,不存完整数据,叶子节点是主键Id的是非聚集索引。

聚集索引也叫聚簇索引,在innodb存储引擎中,主键Id索引就是聚集索引。

他的叶子节点上面包含了数据表一整条完整的数据信息,这就叫聚集索引。

非聚集索引可理解为就是普通的非主键索引,其叶子节点上面不会存储一条完整的数据。

其叶子节点存储的是主键Id,所以我们在使用非聚簇索引时,如果查询完整数据,就需要进行一次回表操作,就是根据叶子节点上存储主键Id,去主键索引里进行回表查询完整的数据。

如果没有主键索引,则会选择第一个非空的索引作为聚集索引,如果没有主键索引,也没有其他的索引,则mysql会创建一个隐藏的rowid作为聚集索引。

为什么数据库主键不建议使用UUID

第一,因为uuid是无序的,在新增一条数据时,uuid因为无序,所以是插入在索引树中间部位的,这就导致这条数据后面的所有数据都需要进行重排,去保持索引的有序,这就导致插入的效率很低。

第二,uuid的长度为36个字节,相比于自增、雪花id等的8个字节相对较长,占用空间更多,也就导致索引数据结构里的一个索引页存储索引字段更少,导致了查询需要进行更多次数的io,效率相对自增和雪花id这类有序递增的id要低。

说一说你对explain的使用理解

type等级尽量达到range级别以上,然后rows尽可能的小,filtered列尽可能的大

在MySQL数据库里explain可以用来查看SQL语句的执行计划,然后可以根据其参数进行优化SQL。

核心重要的是id确定执行顺序(id大的先执行,相同的则排上面的先执行)、type执行性能等级、key预计会走的索引、key_len组合索引命中的字段数量、rows预估扫描数据行、extra会有一些参数,可以根据这些参数提示进行SQL优化例如using filesort,则标识排序用的是文件排序,可以给排序字段添加索引。

Using where表明存储引擎返回了数据之后,在Server层还进行过滤,如果rows的值很大,则说明索引的过滤效果不好,需要进行索引调整。

其中type等级尽量达到range级别以上,然后rows尽可能的小,filtered列尽可能的大(最大100,表明扫描的数据都是可用的)。

mysql索引有几种数据结构类型

我所了解到的mysql索引有BTree和Hash。

Hash数据结构类型的索引只适合进行唯一单字段精确匹配查询,所以基本上很少用它。

BTree数据结构类型是B+树数据结构的一个变种,聚簇索引仅叶子节点存储一行数据的完整信息,一个索引页就能存储更多索引数据,减少比对IO次数,并且,叶子节点之间有互相连接,适合进行范围查询。其3层树就可以存储上千万的数据,性能较好,基本上适合当下业务所有场景。

  1. 每种索引数据结构类型有什么区别?
  2. B树或者B+树的工作原理
  3. 既然你刚刚说了B+树性能高,那为什么不把所有树都换成B+树,还要红黑树二叉树干嘛?
  4. Mysql索引什么时候会失效
  5. 大型项目中,mysql的主键需要全局唯一怎么办
  6. 你刚刚说到了雪花算法,实现原理你知道吗?
  7. 为什么雪花算法比UUID好,好在哪里?
  8. MySQL的事务你说一下对他的理解,他有几种隔离级别
  9. 分布式事务你是怎么实现的
  10. 脏读和幻读的区别