MySQL 八股文面试题
常用的连接池有哪些,他们有什么区别
HikariCP:最轻量、最快,Spring Boot 默认,推荐优先使用
Druid:阿里巴巴开源,性能稍逊,但功能丰富,尤其是监控、统计、SQL 防注入,适合对 安全性和运维监控 要求高的项目(牺牲少量性能换取了监控功能)
C3P0 / DBCP:曾经流行,现在基本不推荐用,除非是老项目

sql的执行流程简单说一下
- 连接器:MySQL内部的连接池
- 查询解析器:将SQL语句解析成语法树(类似于编译器)
- 预处理器:预处理检查表/列是否存在,是否有权限,并将表别名解析为表名
- 查询优化器:将解析后的SQL转换为执行计划,决定走不走索引,走哪个索引,表连接顺序
- 执行器:根据优化器生成的执行计划,调用存储引擎 API,逐步取出数据并返回给客户端

常用的存储引擎和区别说一下
MEMORY:将数据存储在内存中,用于高速读写操作,数据在服务器重启或表被重建时会丢失
MyISAM:不支持事务、外键、行级锁,只支持表级锁,采用非聚簇索引,会存储表的总行数
InnoDb:支持事务、外键、行级锁,也支持表级锁,采用聚簇索引和非聚簇索引,但不会存储表的总行数
什么是mysql的索引,索引的底层结构是什么
索引是帮助MySQL高效获取数据的排好序的数据结构,底层数据结构是b+树
mysql页是什么?
InnoDB 存储的最小单位是 页(Page),默认大小 16KB
索引是什么意思?
是帮助MySQL高效获取数据的排好序的数据结构
b+树和b树有什么区别?
b树所有节点都存储数据,b+树只有叶子节点存储数据,可以保证树高只有2~4层,提高查询速度;并且MySQL的b+树叶子节点使用双向链表连接,提高范围查询速度
mysql有哪些索引?
数据结构角度:B+树索引、Hash索引、全文索引
物理存储角度:聚簇索引、非聚簇索引
索引类型:主键索引、唯一索引、普通索引、联合索引、全文索引
聚簇索引是什么意思?
索引结构包含所有数据的索引,InnoDB中的主键索引就属于聚簇索引。
回表是什么意思?
在使用非聚簇索引时,为了取到具体数据,则需要通过PK(主键索引)回到聚集索引里去查询数据。这个就叫回表查询。扫描了2次索引树。所以效率相对较低。
索引覆盖是什么?
当一次 SQL 查询所需的所有列,都能从索引中直接获取,而不用回表到数据页(表里)取数据时,这个查询就叫做覆盖索引查询。
索引下推是什么?
索引下推是 MySQL 5.6 引入的一种优化技术,在 存储引擎层 就提前利用索引里已有的字段来判断 WHERE 条件,筛掉不满足的记录,减少回表次数
索引为什么不能过多?
- 写操作开销增大,需要维护索引
- 占用存储空间
- 优化器选择困难
主键索引为什么建议用自增id
为了避免页分裂。
因为主键id存储了全量数据,会导致每页存储数据少而页很多,从中间插入时需要改变的页也会更多。
什么是页分裂?
B+Tree 的页满了,又要在中间插入新记录时,MySQL 会:
- 把原页拆成两个页;
- 移动部分数据到新页;
- 更新上层索引指针。
问题:写入性能下降(涉及大量内存和磁盘操作)。
最左前缀原则是什么?
只要查询条件从联合索引的最左边列开始,且各列在条件中连续出现(顺序可以颠倒),MySQL 就能把索引利用到。一旦跳过了某一列,右边所有列都无法再走索引。
“带头不能少,中间不能断,范围后面全完蛋。”
什么是索引合并?
当一个查询条件涉及多个不同索引时,MySQL 优化器可以 同时使用多个索引,再把结果集 合并,从而避免全表扫描。
什么是事务?
一组操作要么全部成功,要么全部失败
事务的特性是什么?
ACID
原子性(Atomicity):事务是最小执行单位,要么全做,要么全不做。
一致性(Consistency):事务执行前后,数据库必须从一个一致状态到另一个一致状态。
隔离性(Isolation):多个事务并发时,互不干扰。
持久性(Durability):事务一旦提交,修改就永久保存,不会因宕机丢失。
mysql怎么保证数据一致性的?
MySQL 对数据一致性的保证是 ACID 特性协同作用的结果:
- 原子性通过 undo log 确保操作的完整性;
- 隔离性通过锁和 MVCC 控制并发干扰;
- 持久性通过 redo log 保证提交后的数据安全;
- 最终通过这些机制,使数据库从一个一致状态(事务开始前)可靠地过渡到另一个一致状态(事务提交后)。
mysql事务并发会有哪些问题?
- 脏读:事务 A 读取到事务 B 未提交的修改(若 B 回滚,A 读取的数据是 “脏数据”)。
- 不可重复读:事务 A 多次读取同一数据,期间事务 B 修改并提交了该数据,导致 A 两次读取结果不一致。(修改导致两次读取的不一致)
- 幻读:事务 A 按条件查询数据,期间事务 B 插入 / 删除了符合条件的新数据,导致 A 再次查询时结果集增多 / 减少(类似 “幻觉”)。(增删导致的两次读取不一致)
mysql的事务特性分别是怎么实现的?
- 原子性 → undo log;
- 一致性 → 原子性 + 隔离性 + 持久性协同;
- 隔离性 → 锁机制(当前读)+ MVCC(快照读 + ReadView);
- 持久性 → redo log。
mysql的隔离级别有哪些?
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 可能 | 可能 | 可能 |
| 读已提交 | 不可能 | 可能 | 可能 |
| 可重复读(默认) | 不可能 | 不可能 | 极大避免(通过锁机制) |
| 可串行化 | 不可能 | 不可能 | 不可能 |
mysql默认的隔离级别有哪些?
- 读未提交(Read Uncommitted):事务可读取其他未提交事务的修改。
- 读已提交(Read Committed):事务只能读取其他已提交事务的修改。
- 可重复读(Repeatable Read)(默认):事务中多次读取同一数据的结果一致(即使其他事务修改并提交)。
- 串行化(Serializable):事务串行执行,完全避免并发问题。
不同的隔离级别分别解决了什么问题?
- 读未提交(Read Uncommitted):什么问题都没解决
- 读已提交(Read Committed):解决了脏读
- 可重复读(Repeatable Read)(默认):解决了脏读、不可重复读以及部分幻读
- 串行化(Serializable):解决所有问题,但是性能低
什么是mvcc?
MVCC(多版本并发控制)是一种并发控制手段。它通过undolog版本链+readView读视图实现,允许读写操作不冲突(读不加锁,写不阻塞读),从而提高并发性能。
readView是什么?
ReadView(读视图)是 MVCC 中用于判断数据版本可见性的逻辑结构,包含 4 个核心字段:
m_ids:当前活跃事务 ID 集合列表。min_trx_id:活跃事务中最小的 ID。max_trx_id:下一个将分配的事务 ID。creator_trx_id:创建该 ReadView 的事务 ID。
作用:通过比较数据版本的事务 ID 与 ReadView 的字段,判断当前事务能否看到该版本。
可见性判断规则:
- 比最小活跃事务ID小,一定读
- 比最大活跃事务ID大,一定不读
- 在最大最小之间的:
- 在活跃列表(未提交),不读
- 不在列表(已提交),读
什么是快照读和当前读?他们的区别是什么?
- 快照读:读取数据的历史快照(非最新版本),不加锁,性能高。例如普通
SELECT语句。 - 当前读:读取数据的最新版本,且会加锁(防止其他事务修改)。例如
SELECT ... FOR UPDATE、INSERT、UPDATE、DELETE等。
区别:快照读依赖 MVCC,无锁冲突;当前读依赖锁机制,会阻塞其他事务的写操作。
不同隔离级别下生成readView的时机?
- 读未提交:不生成 ReadView,直接读取最新版本。
- 读已提交:每次执行 SELECT 时生成新的 ReadView(因此能看到其他事务已提交的修改)。
- 可重复读:事务中第一次执行 SELECT 时生成 ReadView,后续复用(因此多次读结果一致)。
- 串行化:不依赖 MVCC,通过锁机制实现,无需生成 ReadView。
可重复读怎么解决不可重复读的?
可重复读级别下,事务首次执行SELECT时生成 ReadView,后续所有查询复用该 ReadView。即使其他事务修改数据并提交,当前事务仍通过最初的 ReadView 判断可见性,因此多次读取结果一致,避免了不可重复读。
mysql的锁有哪些类型
表锁、行锁
共享锁、排他锁
意向锁
记录锁、间隙锁、临键锁
普通索引的行锁是怎么加锁的?

数据更新的流程是怎么样的?
- 缓冲池:先看buffer pool中有没有这条数据,如果有就直接取出来,如果没有,从磁盘加载到buffer pool再操作
- undo log日志:更新前考虑到可能回滚,所以先写一份旧值到undolog
- 更新缓冲池数据:将内存中的数据改为新值,此时数据页和磁盘数据不一致,被标记为脏页
- 记录redo log:先写入redo log buffer,然后按照策略刷盘(定时刷新/事务提交/log buffer写满)
- 写入binlog:记录了所有对数据库进行更改的逻辑操作,可以实现数据库故障的数据恢复
- 两阶段提交:通过两阶段提交最终保证事务的持久性与一致性
- 如果一阶段redolog未刷盘就发生故障,回滚事务
- 如果一阶段redolog刷盘但undolog未刷盘,也回滚事务
- 如果一阶段redolog和undolog都刷盘,只有二阶段redolog未写入,依旧认为数据完整,提交事务
- 异步线程刷盘:通过后台的异步IO线程,会在之后某个时间里,随机的把内存buffer pool中的修改后的脏数据给刷回到磁盘上的数据文件里去
mysql的bufferpool是什么?
Buffer Pool 就是 MySQL 的“内存缓存”,把常用的数据和索引页放在内存里,减少磁盘读写。(Buffer Pool 是内存里的临时副本)
redolog是什么和binlog有什么区别?
redolog是物理日志,binlog是逻辑日志
| 维度 | Redo Log | Binlog |
|---|---|---|
| 所属层 | InnoDB 存储引擎层 | MySQL Server 层 |
| 日志类型 | 物理日志(记录数据页修改) | 逻辑日志(记录 SQL 逻辑) |
| 作用 | 崩溃恢复(保证 ACID 的 D) | 主从复制、数据备份 |
| 写入时机 | 事务执行中循环写入(循环写) | 事务提交后写入(追加写) |
| 生命周期 | 与数据页刷新绑定 | 可独立归档、删除 |
什么是逻辑日志,什么是物理日志?
- 逻辑日志:记录操作的逻辑含义(如 “将 id=1 的 name 改为 ‘abc’”),与存储格式无关,可读性强。例如 Binlog。
- 物理日志:记录数据页的物理变化(如 “数据页 0x123 的偏移量 100 处值改为 0x55”),依赖存储格式,恢复速度快。例如 Redo Log。
bufferpool的内部结构是怎么样的?
- 缓存页(Page):默认 16KB,与磁盘数据页大小一致,用于存储数据 / 索引。
- 描述信息:每个缓存页对应一个控制块,记录页的元数据(如页地址、表空间 ID、LRU 链表指针等)。
- 链表结构:
- Free 链表:未使用的缓存页列表。
- LRU 链表:管理缓存页的 “冷热”,热点数据(频繁访问)在前端,冷数据在后端,淘汰时从后端移除。
- Flush 链表:已修改但未刷盘的缓存页(脏页)列表,等待刷盘。
mysql对数据页冷热分离是怎么做的?
新加载的数据页一律放在冷数据区的链表头部,等至少 1s 之后再次访问,才会被提升到热区头部
冷数据区37%,热数据区63%(约为6 :4)
mysql行格式是什么,什么是空值列表?
行格式规定一行数据在磁盘和内存中的存储布局。
空值列表是用一个紧凑的标记来记录,这样能大幅节省存储空间,在 COMPACT 行格式中,是用 二进制 bit 位 来标记。
有没有做过mysql的调优,怎么做的?
SQL调优是一个很大的概念,但是大致就是从索引优化、代码/业务优化、架构优化几个方向上来做:
- 比如最常说的索引优化:
- 我们可以使用覆盖索引避免回表;
- 然后就是尽量满足最左匹配原则,避免索引失效;
- 还有就是索引也不宜过多,这样写入的时候维护索引的成本就高了,也占磁盘空间,mysql选择索引的时候也会选择困难
- 再从从代码/业务层面的话:
- 减少sql次数,不在循环发sql,避免频繁数据库IO
- 可以尽量控制事务范围,用小事务避免使用大事务,不在事务中做文件/网络IO操作
- 在业务允许的情况下,使用合适的隔离级别,如RR->RC,避免锁等待
- 在业务上做优化,比如如果需要查询未加索引的情况时,要求用户必填一个加了索引的字段,先筛选掉一部分数据在逐行查询
- 最后就是架构上来说:
- 最容易想到的就是加缓存中间层分担数据库压力,如redis、caffiein、guava
- 可以使用读写分离、分库分表(注意数据库主键与业务主键分离)+使用OLAP数据库定时归档减少OLTP数据库的数据量来分担数据库压力
- 还可以通过升级数据库版本、采用性能更好的连接池来优化
mysql8.0对比5.7有哪些提升?
隐藏索引、窗口函数、更强的 JSON 支持,在线ddl
explain怎么使用,关注哪些字段
在SQL语句前加EXPLAIN关键字就可以看执行计划,主要关注possible_keys(可能用到的索引),key(实际用到的索引),type(用到了哪种索引) ,还有就是Extra(额外信息,提示索引覆盖、索引下推、产生了条件过滤临时表等)




