跳到主要内容MySQL 高频面试题详解 | 极客日志SQL算法
MySQL 高频面试题详解
MySQL 面试的核心知识点,涵盖基础概念、存储引擎区别、索引原理及优化策略。内容包括字符类型差异、事务隔离级别、锁机制、日志系统以及慢查询调优步骤。重点解析了 B+ 树索引结构、MVCC 实现原理、主从复制机制及死锁解决方案,旨在帮助开发者系统掌握数据库面试考点。
片刻1 浏览 一、基础核心篇(初级 / 中级必问)
1. MySQL 是什么?核心特点有哪些?
答案要点:MySQL 是一款开源的关系型数据库(RDBMS),基于 SQL 语言,主打轻量、高性能、高可用、易部署,是互联网行业首选的数据库。核心特点:
- 支持关系型数据库特性:ACID 事务、外键、约束、多表关联查询。
- 高性能:底层优化优秀,支持海量数据存储,单表千万级数据查询依然高效。
- 多存储引擎:支持插件式引擎,最常用 InnoDB(默认)、MyISAM。
- 高可用:支持主从复制、读写分离、集群部署,避免单点故障。
- 跨平台:支持 Linux/Windows/Mac,适配所有主流服务器系统。
2. MySQL 中 InnoDB 和 MyISAM 存储引擎的区别?
✅ 核心结论:MySQL 5.5 及以后,默认存储引擎是 InnoDB。InnoDB 是事务安全型引擎,MyISAM 是性能型引擎,MyISAM 已被官方逐步淘汰。
3. char 和 varchar 的区别?varchar(5) 和 varchar(200) 的区别?
答案要点:二者都是字符串类型,核心区别是存储方式和长度固定性。
✔ 一、char 与 varchar 核心区别
- char(n):定长字符串,n 代表固定长度(0-255)。
- 特点:无论存入多少字符,都会占用 n 个字符的空间,不足补空格;查询速度极快,适合短字符串、长度固定的场景。
- 适用:手机号、身份证号、性别、状态码。
- varchar(n):变长字符串,n 代表最大长度(0-65535)。
- 特点:实际占用空间 = 真实字符长度 + 1/2 个字节(存储长度),不会补空格;查询速度略慢于 char,适合长度不固定的长字符串。
- 适用:用户名、商品标题、描述、地址等。
✔ 二、面试坑点:varchar(5) 和 varchar(200) 存储 "abc" 的区别?
- 存储:两者存入 "abc" 时,实际占用的字节数完全相同。
- 性能:MySQL 只会校验「是否超过最大长度」,不会因为定义的长度大而浪费空间或变慢。
- 注意:不要无脑定义
varchar(255/65535),要按需定义,避免字段长度溢出、索引失效。
4. datetime 和 timestamp 的区别?
答案要点:二者都是日期时间类型,核心区别是存储范围、时区支持、占用空间:
- datetime:占 8 字节,存储范围
1000-01-01 ~ 9999-12-31,不支持时区转换,存入什么时间就显示什么时间。
- timestamp:占 4 字节,存储范围
1970-01-01 ~ 2038-01-19,支持时区转换,存入时会转成 UTC 时间,查询时按当前时区转回。
适用场景:业务无时区需求 → 用 datetime;有跨国/跨时区需求 → 用 timestamp;推荐用 datetime,避免 2038 年溢出问题。
5. 主键、唯一索引、普通索引、外键的区别?
✔ 核心定义 + 区别
- 主键索引(Primary Key)
- 特性:一张表只能有一个主键,主键字段非空 + 唯一,InnoDB 中主键是聚簇索引,数据按主键排序存储。
- 作用:唯一标识一条记录,是表的核心索引。
- 唯一索引(Unique Key)
- 特性:一张表可以有多个唯一索引,索引字段唯一但可以为空(最多一个 null)。
- 作用:保证字段值的唯一性,如手机号、邮箱。
- 普通索引(Index)
- 特性:一张表可以有多个普通索引,字段值可重复、可空,无约束性。
- 作用:单纯提升查询速度。
- 外键索引(Foreign Key)
- 特性:建立两张表的关联关系,外键字段的值必须是另一张表的主键值。
- 注意:生产环境慎用外键,一般在业务层保证关联完整性即可。
✔ 面试加分
- 主键可以是唯一索引,唯一索引不一定是主键。
- 主键字段建议用自增整型(int/bigint),不要用字符串,提升索引效率。
6. 什么是索引?索引的作用?为什么索引能提升查询速度?
✔ 索引定义
索引是 MySQL 的一种特殊数据结构(B+ 树),建立在表的一个或多个字段上,索引存储了字段的值和对应的行数据地址。
✔ 索引的核心作用
- 提升查询速度:通过索引快速定位到数据行,避免全表扫描。
- 加速排序 / 分组:索引本身是有序的,order by/group by 时可直接用索引排序。
- 保证数据唯一性:主键、唯一索引可以约束字段唯一性。
✔ 索引提速的本质
- 无索引:查询时是全表扫描,逐行匹配条件,时间复杂度 O(n)。
- 有索引:通过 B+ 树的有序结构,二分查找定位数据,时间复杂度 O(logn)。
✔ 索引的缺点
- 增删改变慢:数据变更时,需要同步维护索引结构。
- 占用磁盘空间:索引是独立的文件,会占用额外的磁盘空间。
- 过度索引会导致索引失效:不合理的索引会让 MySQL 优化器选择错误的索引。
7. 最左匹配原则是什么?
- 定义:最左匹配原则是联合索引的核心规则,当创建 (a,b,c) 的联合索引时,MySQL 会优先匹配索引的最左侧字段,并依次向右匹配,跳过的字段会导致索引失效。
- 核心规则:
- 支持:
where a=1、where a=1 and b=2、where a=1 and b=2 and c=3 → 全匹配索引。
- 失效:
where b=2、where c=3、where b=2 and c=3 → 跳过了最左的 a,索引完全失效。
- 部分生效:
where a=1 and c=3 → a 字段走索引,c 字段不走索引。
- 延伸规则:联合索引中,范围查询(>、<、like)后的字段会失效。
- 例如:
where a=1 and b>2 and c=3 → a、b 走索引,c 字段失效。
✅ 面试结论:创建联合索引时,把查询频率最高、筛选性最强的字段放在最左侧。
二、进阶原理篇(中 / 高级必问)
1. MySQL 索引的底层数据结构是什么?为什么用 B+ 树?
✔ 一、InnoDB 索引的底层结构:B+ 树
- 普通索引:叶子节点存储「字段值 + 主键值」。
- 主键索引(聚簇索引):叶子节点存储「主键值 + 整行数据」。
✔ 二、为什么 MySQL 选择 B+ 树?
✅ 对比 1:为什么不用【哈希索引】?
- 哈希索引只支持等值查询(=、in),不支持范围查询。
- 哈希索引是无序的,无法用于排序。
- 哈希冲突严重时查询效率暴跌。
✅ 对比 2:为什么不用【二叉树 / 红黑树】?
- 二叉树:极端情况下会退化成单链表,查询效率从 O(logn) 变成 O(n)。
- 红黑树:树的高度过高,千万级数据时树高可达几十层,磁盘 IO 次数过多。
✅ 对比 3:为什么不用【B 树】,而用 B+ 树?
- B+ 树的非叶子节点只存索引,不存数据:一页能存更多索引,树的高度更低,磁盘 IO 次数更少。
- B+ 树的叶子节点是双向链表:支持范围查询,这是 B 树没有的核心优势。
- B+ 树的查询效率稳定:所有查询都要走到叶子节点,查询时间固定。
✅ 面试总结:B+ 树完美适配 MySQL 的「磁盘 IO」和「范围查询」两大核心需求,是最优解。
2. MySQL 事务的四大特性(ACID)?
答案要点:事务是数据库中一组不可分割的 SQL 操作,要么全部执行成功,要么全部失败回滚。
- 原子性(Atomicity):事务中的所有操作是一个整体,要么全成功,要么全回滚。
- 一致性(Consistency):事务执行前后,数据库的数据完整性、业务规则保持不变。
- 隔离性(Isolation):多个事务并发执行时,事务之间相互隔离,互不影响。
- 持久性(Durability):事务提交后,修改的数据会永久写入磁盘,即使数据库崩溃重启,数据也不会丢失。
3. 并发事务会产生哪些问题?MySQL 的事务隔离级别有哪些?
✅ 核心逻辑:事务隔离级别就是为了解决并发事务的三大问题,隔离级别越高,并发问题越少,性能越低。
✔ 一、并发事务的三大问题
- 脏读:事务 A 读取到了事务 B 未提交的数据。
- 不可重复读:事务 A 中多次读取同一数据,期间事务 B 修改并提交了该数据。
- 幻读:事务 A 中多次执行同一查询条件的 SQL,期间事务 B 新增/删除了符合条件的数据。
✔ 二、MySQL 的 4 种事务隔离级别
- 读未提交(READ UNCOMMITTED):存在脏读、不可重复读、幻读。
- 读已提交(READ COMMITTED,RC):解决脏读,存在不可重复读、幻读。
- 可重复读(REPEATABLE READ,RR):MySQL 默认级别,解决脏读、不可重复读,InnoDB 解决了幻读。
- 串行化(SERIALIZABLE):最高级别,事务串行执行,解决所有问题,但性能极差。
✔ 面试加分:MySQL 的 RR 级别,为什么能解决幻读?
✅ 标准答案:InnoDB 在 RR 级别下,通过「间隙锁 + 临键锁」的组合(Next-Key Lock),锁住了数据的「行 + 区间」,彻底阻止了其他事务的新增/删除操作。
4. InnoDB 的锁机制?行锁、表锁、乐观锁、悲观锁的区别?
✔ 一、InnoDB 的两种核心锁
- 行级锁:锁住表中的某一行数据,其他事务可以操作表中其他行,并发性能极高。
- 触发条件:必须命中索引,如果查询没有走索引,行锁会升级为表锁!
- 表级锁:锁住整张表,其他事务无法操作表中的任何数据,并发性能极差。
- 触发条件:无索引查询、全表扫描、执行 alter table 等 DDL 语句时触发。
✔ 二、乐观锁 & 悲观锁
- 悲观锁(Pessimistic Lock)
- 核心思想:认为每次操作都会有并发冲突,先锁住数据,直到操作完成才释放。
- 数据库实现:
select ... for update。
- 适用场景:写多读少的高并发场景。
- 乐观锁(Optimistic Lock)
- 核心思想:认为每次操作都不会有并发冲突,只在提交时判断数据是否被修改过。
- 实现方式:版本号法,在表中加 version 字段。
- 适用场景:读多写少的场景。
✅ 面试结论:写多读少用悲观锁,读多写少用乐观锁。
5. MySQL 三大日志(redo log、undo log、binlog)的区别和作用?
✔ 一、redo log 重做日志(InnoDB 独有)
- 核心作用:保证事务的持久性,解决「数据库崩溃后数据丢失」的问题。
- 工作原理:数据修改先写入内存,再异步刷盘。为了防止内存数据丢失,每次执行写操作时,都会先把修改记录写入 redo log。
- 特点:物理日志、循环写入、事务提交时刷盘。
✔ 二、undo log 回滚日志(InnoDB 独有)
- 核心作用:保证事务的原子性,实现「事务回滚」和「MVCC 多版本并发控制」。
- 工作原理:执行写操作时,先把「修改前的数据」写入 undo log。
- 特点:逻辑日志、可回滚、支持多版本。
✔ 三、binlog 归档日志(MySQL 服务器层日志)
- 核心作用:实现主从复制和数据备份/恢复。
- 工作原理:记录所有的 DDL 和 DML 语句,以二进制形式存储。
- 特点:逻辑日志、追加写入。
✔ 三者核心区别
- 归属不同:redo/undo 是 InnoDB 引擎层日志,binlog 是 MySQL 服务器层日志。
- 作用不同:redo 保证持久化,undo 保证原子性,binlog 保证主从同步。
- 写入方式不同:redo 循环写,undo/binlog 追加写。
- 内容不同:redo 是物理日志,undo/binlog 是逻辑日志。
6. 什么是 MVCC?实现原理是什么?
- 定义:MVCC = 多版本并发控制,是 InnoDB 在 RR 级别下实现的一种无锁并发控制机制。
- 核心思想:为每一行数据维护多个历史版本,不同事务读取不同版本的数据。
- 实现原理:基于 undo log(历史版本)+ 事务 ID + ReadView(可见性规则)实现。
- 优势:解决了「读锁和写锁的互斥问题」,读操作不用加锁,写操作只加行锁。
三、高级优化 & 实战篇(资深 / 架构师必问)
1. MySQL 慢查询优化的完整步骤?
✅ 核心:面试时回答这个问题,一定要分步骤、有逻辑。
慢查询优化 6 步黄金法则
步骤 1:开启慢查询日志,定位慢 SQL
- 开启慢查询:
slow_query_log = ON,设置阈值:long_query_time = 1。
- 查看慢查询日志:
show slow logs,或用工具 mysqldumpslow 分析。
步骤 2:用 EXPLAIN 分析慢 SQL 执行计划
- 执行
EXPLAIN + 慢SQL,查看关键字段:type、key、rows、Extra。
- 核心判断标准:
type 最优是 const,最差是 ALL;key 为 NULL 表示无索引;rows 行数越少越好。
步骤 3:优化索引
- 针对无索引的慢 SQL:创建合适的索引。
- 针对索引失效的 SQL:修复索引失效问题。
- 针对冗余索引:删除无用的索引。
步骤 4:优化 SQL 语句本身
- 避免写复杂的多表关联,拆分 SQL。
- 避免使用
select *,只查需要的字段。
- 避免使用
%xxx 模糊查询(左模糊会导致索引失效)。
- 大表分页优化:
select * from table where id>10000 limit 10 替代 limit 10000,10。
步骤 5:优化表结构
- 大表拆分:垂直拆分(按字段)、水平拆分(按数据量)。
- 优化数据类型:用小类型替代大类型。
- 分表分库:单表数据量超过千万级时考虑分库分表。
步骤 6:优化 MySQL 配置参数
- 调优内存相关参数:
innodb_buffer_pool_size、join_buffer_size。
- 调优连接相关参数:
max_connections、wait_timeout。
2. 索引失效的 10 种常见场景 + 解决方案?
✅ 核心:索引失效的本质是 MySQL 优化器认为走索引的效率不如全表扫描高。
索引失效场景
- 查询条件中使用函数 / 运算:
where abs(id)=10 → 索引失效;✔ 解决:避免在索引字段上做函数/运算。
- 左模糊查询:
where name like '%abc' → 索引失效;✔ 解决:尽量用右模糊,必须左模糊则用全文索引。
- 联合索引不遵循最左匹配原则:跳过最左字段,索引失效。
- 查询条件中使用 != 或 <>:
where id != 10 → 索引失效。
- 查询条件中使用 is null /is not null:索引字段为 null 时,索引失效。
- 使用 in /not in /or:
where id in (1,2,3) → 索引失效;✔ 解决:大数据量用 exists 替代。
- 数据分布不均:区分度太低,不创建索引。
- 查询条件没有命中索引:行锁升级为表锁。
- 隐式类型转换:字段是 int 类型,查询时传字符串 → 索引失效。
- 优化器选择错误:用
force index(索引名) 强制走索引。
3. 大表如何优化?单表数据量多大需要优化?
✔ 一、优化阈值
- 行业共识:单表数据量超过 1000 万行 或 表文件超过 10G,查询性能会急剧下降。
✔ 二、大表优化的 6 种方案
✅ 方案 1:优先做「非分表优化」
- 加合适的索引。
- 优化 SQL:避免 select *、避免大表关联。
- 冷热数据分离:将历史冷数据归档到历史表。
- 开启分区表:按时间/范围分区。
✅ 方案 2:分表优化
- 垂直分表:按字段拆分,如订单基本信息表和订单详情表。
- 水平分表:按数据行拆分,如按用户 ID 哈希拆成多张表。
✅ 方案 3:分库分表
当单库的存储和性能达到瓶颈时,采用分库分表,主流中间件:Sharding-JDBC、MyCat。
4. MySQL 主从复制的原理?主从延迟的原因和解决办法?
✔ 一、主从复制的核心原理
- 主库:主库执行写操作后,将 SQL 语句写入 binlog 日志。
- 从库:从库的 IO 线程连接主库,读取主库的 binlog 日志,写入本地的 relay log 中继日志。
- 从库:从库的 SQL 线程读取中继日志,执行其中的 SQL 语句。
✔ 二、主从延迟的原因 + 解决方案
✅ 主从延迟的核心原因
- 主库写操作并发量高,从库处理速度慢。
- 从库硬件配置比主库差。
- 主库执行大事务。
- 主从复制是异步的,天生存在延迟。
✅ 主从延迟的解决方案
- 提升从库配置。
- 减少大事务:拆分大事务为小事务。
- 半同步复制:开启
rpl_semi_sync_master。
- 并行复制:从库开启多线程并行执行 SQL。
- 业务层优化:实时查询走主库,非实时查询走从库。
5. 什么是死锁?死锁的产生原因和解决办法?
✔ 一、死锁的定义
死锁是指两个或多个事务,互相持有对方需要的锁,同时等待对方释放锁,导致所有事务都无法继续执行。
✔ 二、死锁的产生条件
- 互斥:同一时刻,一个锁只能被一个事务持有。
- 持有并等待:事务持有一个锁,同时申请另一个锁。
- 不可抢占:锁只能由持有事务主动释放。
- 循环等待:事务之间形成循环的锁等待关系。
✔ 三、死锁的解决办法
✅ 预防死锁
- 统一事务的加锁顺序。
- 减少锁的持有时间。
- 尽量用行锁,少用表锁。
- 避免大事务。
✅ 解决死锁
- MySQL 会自动检测死锁,并回滚其中一个事务。
- 手动处理:通过
show engine innodb status 查看死锁日志。
✅ 面试加分小技巧
- MySQL 面试的核心是「索引 + 事务 + 锁 + 优化」,这四个模块占比 90%。
- 回答问题时,分点作答,逻辑清晰。
- 遇到原理题,讲清楚核心流程和优势即可。
- 所有优化类问题,都要遵循「先低成本,后高成本」的原则。
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- SQL 美化和格式化
在线格式化和美化您的 SQL 查询(它支持各种 SQL 方言)。 在线工具,SQL 美化和格式化在线工具,online
- SQL 转 CSV/JSON/XML
解析 INSERT 等受限 SQL,导出为 CSV、JSON、XML、YAML、HTML 表格(见页内语法说明)。 在线工具,SQL 转 CSV/JSON/XML在线工具,online
- CSV 工具包
CSV 与 JSON/XML/HTML/TSV/SQL 等互转,单页多 Tab。 在线工具,CSV 工具包在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online