> 技术文档 > MySQL八股篇

MySQL八股篇


查询关键字执行先后顺序
  • FROM(及 JOIN)

  • WHERE

  • GROUP BY

  • HAVING

  • SELECT

  • DISTINCT

  • ORDER BY

  • LIMIT / OFFSET

CHAR 和 VARCHAR 的区别?使用场景?
特性 CHAR VARCHAR ​存储方式​​ 定长,存储时填充空格至定义长度 变长,存储实际数据 + 长度前缀 ​空间占用​​ 固定(可能浪费空间) 动态(节省空间) ​​读取性能​​ 高(无需解析长度,直接读取固定长度) 较低(需解析长度前缀) ​适用场景​​ 长度固定的字段(如编码、枚举) 长度不固定的文本(如描述、地址)
MySQL窗口函数是什么

对数据集划分窗口(比如按组、按排序范围),在窗口内计算并返回每行对应的结果,​​不聚合数据​​,保留所有行

explain语句执行后生成的表重要字段含义
字段 含义 常见取值 / 说明 type 访问类型(效率从好到差) system > const > eq_ref > ref > range > index > ALL key 实际使用的索引 索引名,如 idx_amountNULL 表示未命中索引(全表扫描) rows 优化器估算需扫描的行数 数值越大,意味着扫描量越大,通常要尽量降低 Extra 额外操作信息 如 Using whereUsing index(覆盖索引)、Using filesortUsing temporary
索引是什么?有什么好处?
  • 是一种能高效获取数据的数据结构

  • 可以提高数据检索效率,降低数据库的 I/O 成本

  • 可以对数据进行排序,降低数据排序的成本,减少CPU的消耗

MySQL 索引失效的情况
  • 模糊匹配时 % 开头
SELECT * FROM tbl WHERE name LIKE \'%ohn\';
  • 对列进行函数运算或表达式计算
SELECT * FROM tbl WHERE DATE(created_at) = \'2025-06-27\';
  • 字符串值不加引号,索引失效
-- phone 不加引号,索引失效explain select * from tb_user where phone = 17799990015;
  • or 两边条件,一边有索引,一边无索引,索引失效
-- id 有索引、age 无索引,索引失效explain select * from tb_user where id = 10 or age = 23; 
MySQL索引使用会出现什么问题?该怎么解决?

问题:

  • 索引维护成本高,影响写入性能, 解决: 减少索引数量, 批量提交写入操作,减少索引更新次数

  • 索引未被使用(索引失效), 解决: 优化查询语句

  • 索引占用过多磁盘空间 , 解决: 精简索引字段,清除无用索引

事务四大特性(ACID)及实现原理​​
​特性​​ ​描述​​ ​​实现原理​​ ​​原子性 事务要么全部成功,要么全部回滚 通过回滚日志(​Undo Log)实现​​ ​一致性 ​ 事务执行前后数据库的完整性约束不变 通过持久性+原子性+隔离性实现 ​​隔离性 ​ 并发事务之间互不干扰 ​​通过锁机制​​和 ​MVCC​(​多版本并发控制)实现 ​​持久性 ​ 事务提交后数据永久保存 ​通过重做日志(Redo Log)实现
​并发事务问题​​

并发事务可能导致脏读、不可重复读和幻读

  • 脏读是指一个事务读到了另一个事务未提交的“脏数据”
  • 不可重复读是指在一个事务内多次读取同一数据,由于其他事务的修改导致数据不一致
  • 幻读是指一个事务读取到了其他事务插入的“幻行”
​事务隔离级别及实现原理​​
​​隔离级别​​ ​​脏读​​ ​不可重复读​​ ​​幻读​​ ​​实现原理​​ ​​读未提交 ✔ ✔ ✔ 无锁,直接读取最新数据(包括未提交的数据) ​读已提交 ​​ ✘ ✔ ✔ ​​MVCC​​:每次查询生成独立的ReadView,仅读取已提交的数据版本 ​​可重复读 ​​ ✘ ✘ ✔ ​​MVCC​​:事务首次查询生成ReadView,后续复用该视图(MySQL默认隔离级别) ​​串行化​​ ✘ ✘ ✘ ​​锁机制​​:所有操作加锁,事务串行执行
事务隔离级别,每个级别会引发什么问题,MySQL 默认是哪个级别?
  • MySQL 默认事务隔离级别是可重复读

事务隔离级别引发的问题:

隔离级别 描述 可能出现的问题 READ UNCOMMITTED(读未提交) 允许读取其他事务未提交的数据。 脏读、不可重复读、幻读 READ COMMITTED(读已提交) 只能读取其他事务已提交的数据。 不可重复读、幻读 REPEATABLE READ(可重复读) 同一事务中多次读取的数据一致。 幻读 SERIALIZABLE(串行化) 强制事务串行执行,完全隔离。 无,但性能较低,可能导致并发性差
MySQL 常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
特性 InnoDB MyISAM MEMORY 事务 支持 不支持 不支持 锁机制 支持行级锁, 适合高并发读写场景 支持表级锁,适合读多写少、简单查询场景 支持表级锁,适合临时高速缓存表 外键与完整性 支持外键约束 不支持外键 不支持外键 崩溃恢复 支持崩溃恢复 无崩溃恢复机制 不支持恢复
  • InnoDBMySQL 5.5 开始为默认存储引擎,综合事务处理能力和恢复性能最好。适合高并发读写、事务处理要求高的场景

  • MyISAM 适合读操作多、写操作较少, 对事务和数据完整性要求不高的场景

  • MEMORY 引擎速度最快,只作为短期缓存或临时表使用,不用于持久化业务数据

什么是聚簇索引什么是非聚簇索引?
  • 聚簇索引是指数据与索引放在一起,B+ 树的叶子节点保存了整行数据,通常只有一个聚簇索引,一般是由主键构成

  • 非聚簇索引则是数据与索引分开存储,B+树的叶子节点保存的是主键值,可以有多个非聚簇索引

回表查询是什么?

指的是通过二级索引找到对应的主键值,然后再通过主键值查询聚簇索引中对应的整行数据的过程

MySQL 中为什么推荐使用连接查询而不是子查询?

连接查询比子查询更高效、可读性更好, 因为连接查询不需要额外的中间临时表,但是子查询有中间临时表

什么叫覆盖索引?
  • 指的是在 SELECT 查询中,返回的列都能在索引中找到

  • 好处: 避免了回表查询,提高了性能。使用覆盖索引可以减少对主键索引的查询次数,提高查询效率

表的查询速度很慢,怎么解决?
  • 使用 explain 分析 sql 语句,找出原因

  • 创建, 优化索引

  • 优化数据库表,如果表数据量过大,可以拆成多张表

  • 使用缓存

索引创建原则?
  • 表中的数据量超过 10万 以上时考虑创建索引

  • 选择查询频繁的字段作为索引,如查询条件、排序字段或分组字段

  • 对于内容较长的字段使用前缀索引

  • 控制索引数量,虽然索引可以提高查询速度,但会影响插入、更新的速度

  • 尽量使用联合索引,覆盖 SQL 的返回值, 比如查询 WHERE user_id=100 AND status=1,创建(user_id, status)的联合索引,比单独给两个字段建索引更能精准定位数据, 如果复合索引包含了 SELECT 语句需要返回的所有字段(如SELECT id, name FROM t WHERE user_id=100,索引设为(user_id, id, name)),数据库可以直接从索引中获取数据,无需再去表中查询(避免 “回表” 操作),大幅减少 IO 开销

SQL的优化手段
  • 建表时选择合适的字段类型

  • 使用索引,优化索引

  • 编写高效的SQL语句,比如避免使用SELECT *,尽量使用UNION ALL代替UNION,以及在表关联时使用INNER JOIN

  • 采用主从复制和读写分离提高性能

  • 在数据量大时考虑分库分表

MySQL的binlog​​
  • ​二进制日志,记录所有数据库的​写操作​(DDL/DML
  • ​​作用​​:主从复制(数据同步), 数据恢复(通过 mysqlbinlog 工具回放日志)
undo log 和 redo log 的区别是什么?
  • redo log 记录的是数据页的物理变化,用于服务宕机后的恢复,保证事务的持久性
  • undo log 记录的是逻辑日志,用于事务回滚时恢复原始数据,保证事务的原子性和一致性
​为什么使用B+ 树作为索引?​而不用哈希表或二叉树​

B+ 树 优势​:

  • B + 树 的高度低, 磁盘 IO 次数少

  • ​​查询高效​​, 叶子节点形成有序链表,能够快速遍历

  • ​​查询效率稳定​, 所有查询路径长度相同,时间复杂度稳定为 O(log n)

​对比其他结构​:

  • 哈希表​不支持范围查询,哈希冲突影响性能

  • 二叉树​:树高较高,I/O次数多,可能退化为链表

​​日志与恢复​​
​​日志​​ ​​作用​​ ​​应用场景​​ ​​Redo Log​​ 记录事务对数据页的物理修改,保证持久性。 崩溃恢复时重放未刷盘的修改。 ​​Undo Log​​ 记录事务前的数据逻辑状态,用于回滚和MVCC。 事务回滚、多版本读。 ​​BinLog​ 记录所有数据库写操作(逻辑日志),用于主从复制和数据恢复。 数据同步(如MySQL主从)、数据恢复。
事务中的隔离性是如何保证的呢?(解释下MVCC)

事务的隔离性通过锁和多版本并发控制(MVCC)来保证。MVCC 通过维护数据的多个版本来避免读写冲突。底层实现包括隐藏字段、undo logread view。隐藏字段包括trx_idroll_pointerundo log记录了不同版本的数据,通过roll_pointer形成版本链。read view定义了不同隔离级别下的快照读,决定了事务访问哪个版本的数据。

MySQL主从同步原理是什么?

MySQL主从复制的核心是二进制日志(Binlog)。步骤如下:

  1. 主库在事务提交时记录数据变更到Binlog

  2. 从库读取主库的Binlog并写入中继日志(Relay Log)

  3. 从库重做中继日志中的事件,反映到自己的数据中

​ 执行一条SQL的流程​​
  1. ​​连接器​​:验证用户权限,建立连接
  2. ​​查询缓存​​:检查缓存(MySQL 8.0已移除)
  3. ​​解析器​​:语法分析,生成抽象语法树(AST)
  4. ​​优化器​​:选择最优执行计划(如索引选择、JOIN顺序)
  5. ​​执行器​​:调用存储引擎接口执行计划
  6. ​​存储引擎​​(如InnoDB):
    • 从内存(Buffer Pool)或磁盘读取数据
    • 写入Redo Log和Undo Log
  7. ​​返回结果​​:将结果返回客户端
如何在MySQL中查看慢查询?
  • 开启慢查询日志

  • 使用 SHOW PROCESSLIST 实时监控​