ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Java后端面试MySQL核心考点:索引、事务、锁与SQL优化全解析

2026/8/31 10:59:34 拓冰建站 浏览量
Java后端面试MySQL核心考点:索引、事务、锁与SQL优化全解析 8 月这个时间点很多同学都在集中准备 Java 后端面试MySQL 往往是复习计划里最容易“背了忘、忘了背”的一块。网上的 MySQL 面试题零零散散要么只有结论没有原理要么全是“八股文”式的背诵清单一旦面试官追问“为什么”很容易卡壳。本文打算换一种复习方式不再单独罗列面试题而是按面试官追问的主线把 MySQL 高频考点拆成一条完整链路存储引擎、索引、事务、锁、SQL 优化、慢查询最后再给一份可以直接背的高频问答和避坑清单。如果你是正在准备 Java 面试的求职者或者已经复习过一轮但知识点比较散想系统串一遍 MySQL 核心内容这篇文章可以帮你节省不少时间。读完以后你不只是记住几个面试题答案还能理解“一条 SQL 为什么走索引”“RR 隔离级别为什么能解决幻读”“慢查询该怎么排查”这类底层逻辑。1. 为什么 Java 面试绕不开 MySQL1.1 MySQL 在后端技术栈中的位置大多数 Java 后端项目关系型数据库选型就是 MySQL这一点在中小型公司、互联网初创团队甚至部分大型系统里都非常常见。业务数据、订单记录、用户信息、配置数据几乎都落在 MySQL 里。面试官考察数据库能力时自然优先从 MySQL 入手。MySQL 面试题不是单纯考“你会不会写 SQL”而是通过一系列问题判断你对数据存储、并发控制、查询优化的理解深度。比如同样问“为什么用 B 树”有人只回答“查询快”有人能从磁盘 IO、树高、范围查询、聚簇索引多个角度展开两者在面试官心中的印象完全不同。1.2 面试官到底想通过 MySQL 问出什么可以把 MySQL 考察内容分成四个层次第一个层次SQL 基础是否熟练。增删改查、聚合查询、多表连接、子查询、分组排序这些是最基本的能力。第二个层次建表建模能力和查询优化意识。会不会设计合理的表结构、能不能根据查询场景建索引、有没有看过执行计划。第三个层次并发与事务理解。事务隔离级别、脏读、不可重复读、幻读、MVCC、锁机制这些是 Java 后端面试的高频区也是区分度最大的部分。第四个层次高可用与分布式扩展。主从复制、分库分表、读写分离、binlog 应用这一类通常在中高级岗位或项目深挖环节出现。对大多数 Java 后端岗位第一到第三层次属于必问范围。本文重点覆盖前三个层次并在高频题库里补充第四个层次的基础概念方便你应对不同面试风格。1.3 复习主线从一条 SQL 的执行过程开始MySQL 面试题看起来很多但核心知识点之间其实是互相串联的。最好的复习方式是围绕“一条 SQL 从客户端发出到存储引擎返回结果”这条主链路展开。这条链路上你会遇到连接器、分析器、优化器、执行器会碰到存储引擎为什么要区分 InnoDB 和 MyISAM会走进索引理解 B 树为什么高效会进入事务理解隔离级别和 MVCC会接触锁理解并发控制最后还要掌握慢查询和 Explain用来排查性能问题。整篇文章就是按这条主线设计的。2. 环境准备本地搭一套可复现的 MySQL 练习环境面试准备不能只看文章最好在本地准备好一套 MySQL 练习环境把索引失效、事务隔离级别、死锁、慢查询这些场景亲手跑一遍。这样印象更深面试时也能说出“我复现过”的细节。2.1 安装 MySQL推荐使用 Docker本地安装 MySQL 有很多方式最省心的是用 Docker。一条命令即可启动一个 MySQL 8.x 实例用完可以随时删掉重建不影响本机环境。docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:8.0启动后进入容器连接到 MySQLdocker exec -it mysql8 mysql -uroot -p123456需要注意几点MySQL 8.x 默认认证插件是 caching_sha2_password如果项目里用 Java 连接建议使用 mysql-connector-j 8.x 版本驱动避免出现认证协议不兼容的报错。如果同时跑多个 MySQL 实例记得修改端口避免 3306 冲突。生产环境不要直接用简单密码本地测试无所谓。如果你已经在 Windows 或 Linux 上安装过 MySQL完全可以直接用本地环境命令和 SQL 都兼容。版本说明本文章的 SQL 示例基于 MySQL 8.x 编写MySQL 5.7 大部分也适用但个别功能存在差异请以你的实际环境为准。2.2 准备示例表为了验证索引和事务建议建两张简单的业务表用户表和订单表。CREATE DATABASE IF NOT EXISTS interview_demo DEFAULT CHARSET utf8mb4; USE interview_demo; CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL DEFAULT , age INT NOT NULL DEFAULT 0, city VARCHAR(50) NOT NULL DEFAULT , create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE order ( id INT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL DEFAULT 0, amount DECIMAL(10,2) NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待支付 1已支付 2已取消, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这两张表结构很简单但足够演示索引、连接查询、事务、Explain 等场景。你可以根据自己的需求继续插入测试数据。2.3 开启慢查询日志面试中经常问“慢查询怎么排查”本地环境可以提前把慢查询日志打开。SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1;这两条命令的含义是开启慢查询日志执行时间超过 1 秒的 SQL 会被记录下来。long_query_time 的默认值通常是 10 秒排查问题时可以调低。生产环境不建议随意开启慢查询日志因为会增加磁盘 IO 和性能开销。本地测试环境可以放心使用。3. SQL 执行过程与存储引擎3.1 一条查询 SQL 的执行链路面试官经常问“一条 select 语句在 MySQL 中是怎么执行的”这个问题看起来简单但能回答完整的人并不多。标准的执行链路可以分为以下几步客户端通过网络协议将 SQL 发给 MySQL 服务器。连接器负责建立连接、校验用户名密码、获取权限信息。如果开启查询缓存且命中缓存MySQL 8.0 之前会直接返回结果MySQL 8.0 开始已经移除查询缓存。分析器对 SQL 做词法分析和语法分析检查 SQL 是否符合语法规则。优化器决定使用哪个索引、以什么顺序连接表生成执行计划。执行器调用存储引擎接口逐行读取、判断并返回结果。这个链路对应了不少面试题比如“分析器做了什么”“优化器怎么选索引”“执行器和存储引擎是什么关系”。能把这个流程讲清楚说明你不只是会写 SQL而是理解 MySQL 的整体架构。3.2 InnoDB 与 MyISAM 对比存储引擎是 MySQL 面试的基础题。面试中最常对比的是 InnoDB 和 MyISAM。对比项InnoDBMyISAM事务支持支持 ACID 事务不支持事务锁粒度支持行锁并发能力强只支持表锁外键约束支持外键不支持外键崩溃恢复支持通过 redo log 恢复崩溃后恢复能力较弱聚簇索引是主键索引叶子节点存整行数据不是索引文件和数据文件分离全文索引MySQL 5.6 之后支持原生支持适用场景大多数业务系统尤其需要事务和高并发写入只读、数据仓库类场景这里有一个高频追问为什么 InnoDB 适合高并发核心原因是行锁。MyISAM 使用表锁写一条记录也会锁住整张表写入性能在并发场景下很差InnoDB 支持行级锁多个事务操作不同记录时互不阻塞并发能力更强。加上事务、崩溃恢复等能力InnoDB 成为 MySQL 默认存储引擎是很自然的选择。3.3 存储引擎选择建议新项目默认选择 InnoDB 基本没有争议。即使在读多写少的场景也优先考虑用 InnoDB 缓存方案而不是退回 MyISAM。MyISAM 在只读报表、日志分析这类对事务没要求、写入很少的场景中还有一定使用空间但实际业务系统已经很少首选它。如果你在建表时没有显式指定存储引擎MySQL 8.x 默认就是 InnoDB。这也是面试中一个基础得分点。4. 索引为什么能加速B Tree 与聚簇索引4.1 没有索引时 MySQL 怎么查假设 user 表有 100 万条数据现在要查 name 张三 的记录。如果没有索引MySQL 只能从第一行开始逐行扫描整张表把每一条记录的 name 都取出来比较一次。这个操作叫全表扫描数据量越大耗时越长。索引的本质就是为数据额外建立一种有序的查找结构。通过索引MySQL 可以快速定位到目标数据所在位置避免全表扫描。但索引不是免费的它需要额外的存储空间写入数据时还需要维护索引结构所以索引不是建得越多越好。4.2 为什么 InnoDB 选择 B TreeInnoDB 的索引结构是 B Tree。要理解 B Tree 为什么高效可以先看几个备选方案Hash 索引等值查询非常快但不支持范围查询也无法利用索引排序。哈希冲突多时性能也不稳定。红黑树平衡二叉树在内存中查找很快但树的高度较高。数据量大时每次从磁盘读取一个节点都要一次 IO树越高 IO 次数越多。B-Tree每个节点可以存储多个键树更矮但仍然在非叶子节点保存数据导致单次 IO 能加载的键数量变少。B Tree非叶子节点只存索引键不存数据所以单个节点能存放更多键树更加矮胖叶子节点按顺序排列并通过链表连接支持高效的范围查询。B Tree 牺牲了非叶子节点直接访问数据的特性换来了更低的树高和更强的范围查询能力。一次磁盘 IO 通常能读取一个页页大小默认 16KB非叶子节点只存键值可以大幅减少 IO 次数这就是 B Tree 成为 InnoDB 索引核心结构的原因。4.3 聚簇索引、二级索引、回表、覆盖索引InnoDB 的索引按照存储结构可以分成两类聚簇索引也叫主键索引。InnoDB 中聚簇索引的叶子节点直接存储整行数据。如果你定义了主键主键索引就是聚簇索引如果没有主键InnoDB 会选择一个唯一非空索引作为聚簇索引如果还不行会生成隐藏主键。二级索引也叫非聚簇索引、辅助索引。二级索引的叶子节点存储的是主键值。比如在 name 字段上建立索引索引叶子节点保存的是对应行的主键 id。由于二级索引只存主键值当你通过 name 索引查到主键 id 后还想获取完整行数据就需要再回到聚簇索引里查一次这个动作称为回表。SELECT * FROM user WHERE name 张三;如果 name 上有二级索引上面的 SQL 会先通过 name 索引找到主键 id再通过主键 id 回到聚簇索引查整行数据这就是一次回表。覆盖索引指的是查询字段全部包含在某个二级索引中不需要再回表。比如SELECT id, name FROM user WHERE name 张三;如果 name 索引的叶子节点存了主键 id那么 id 和 name 都能直接从二级索引中获得不需要回表Extra 列会显示 Using index。4.4 联合索引与最左前缀原则联合索引也叫多列索引比如在 (city, age) 两个字段上建索引。面试常考“最左前缀原则”联合索引在查询时必须从最左边的列开始匹配不能跳过。CREATE INDEX idx_city_age ON user(city, age);以下查询能用到这个联合索引SELECT * FROM user WHERE city 上海 AND age 25; SELECT * FROM user WHERE city 上海;以下查询无法用到联合索引SELECT * FROM user WHERE age 25;因为 age 不是联合索引的最左列查询时无法从索引的第一个字段开始匹配。不过要注意是否一定走索引最终还是由优化器根据数据量和成本决定。4.5 常见索引失效场景面试经常问“哪些情况会导致索引失效”但很多答案过于绝对实际需要结合数据量和优化器判断。常见的典型场景有对索引列使用函数比如 WHERE YEAR(create_time) 2024如果 create_time 是索引列函数会导致索引失效。隐式类型转换比如索引列是 varchar查询条件用了数字MySQL 可能无法使用索引。LIKE 以 % 开头比如 WHERE name LIKE %张%因为无法确定前缀难以走索引。OR 连接非索引列比如 WHERE id 1 OR age 20如果 age 没有索引可能直接全表扫描。不满足最左前缀原则。需要记住索引失效不是绝对的优化器会评估成本。面试时主动说清楚这一点会显得更专业。5. 事务隔离级别与 MVCC5.1 ACID 是什么事务是数据库操作的最小逻辑单元要么全部成功要么全部失败。MySQL InnoDB 事务满足 ACID 四个特性原子性事务中的操作要么全部完成要么全部回滚。InnoDB 通过 undo log 实现回滚。一致性事务执行前后数据完整性不能被破坏。一致性是数据库整体目标由应用层和数据库共同保证。隔离性多个事务并发执行时应该像串行执行一样互不干扰。隔离性由锁和 MVCC 实现。持久性事务提交后数据变更要永久保存即使系统崩溃。InnoDB 通过 redo log 保证持久性。面试问答中如果只背 ACID 含义只能算及格。能进一步说出 undo log 与原子性的关系、redo log 与持久性的关系才是加分项。5.2 并发事务带来的三个问题多个事务并发执行时容易出现以下几类数据问题。脏读一个事务读到了另一个事务未提交的数据。比如事务 A 修改了一行数据但还没提交事务 B 读取了这行数据随后事务 A 回滚事务 B 读到的就是无效数据。不可重复读同一个事务内两次读取同一行数据结果不一致。因为其他事务在这期间提交了修改。幻读同一个事务内两次执行相同的查询返回的结果集条数发生了变化。比如事务 A 查询某条件下的记录只有 5 条事务 B 插入了一条新记录并提交事务 A 再次查询变成了 6 条多出来的一行就是“幻行”。这三个问题容易混淆面试时可以用一个简短例子说明避免只背定义。5.3 四个隔离级别SQL 标准定义了四个隔离级别MySQL InnoDB 默认使用可重复读 REPEATABLE READ。隔离级别脏读不可重复读幻读READ UNCOMMITTED 读未提交可能可能可能READ COMMITTED 读已提交不可能可能可能REPEATABLE READ 可重复读不可能不可能可能但 InnoDB 通过 MVCC 和间隙锁解决SERIALIZABLE 串行化不可能不可能不可能读未提交隔离级别下事务可以读到其他事务未提交的数据容易产生脏读实际业务很少使用。串行化隔离级别下事务完全串行执行性能很低只在极端需要强一致的场景使用。MySQL 默认的可重复读隔离级别在快照读场景下通过 MVCC 解决不可重复读和幻读在当前读场景下通过间隙锁解决幻读这一点是面试核心面试官很容易追问。5.4 MVCC 核心原理MVCC 的中文意思是多版本并发控制。简单理解就是让快照读不需要加锁通过数据行的“多个版本”实现一致性读取。InnoDB 的每行数据除了业务字段还有几个隐藏字段DB_TRX_ID最后修改或插入这行数据的事务 ID。DB_ROLL_PTR回滚指针指向 undo log 中的上一个版本。隐藏主键等。每次事务更新一行数据时InnoDB 不会直接覆盖旧值而是把旧值写入 undo log形成一条版本链。新读取一个事务时会根据 ReadView 判断当前事务应该看到版本链上的哪个版本。ReadView 可以理解成“事务快照”里面记录了当前活跃事务列表等信息。当一个事务读取数据时MySQL 会沿着 undo log 版本链查找找到符合可见性规则的第一个版本。这里有一个重要区别在 READ COMMITTED 隔离级别下每次快照读都会生成新的 ReadView所以其他事务提交后当前事务再次读取可以看到新数据出现不可重复读。在 REPEATABLE READ 隔离级别下事务内第一次快照读时生成 ReadView后续快照读复用同一个 ReadView。其他事务提交的新版本对于当前事务不可见因此解决了不可重复读。MVCC 解决的是快照读场景下的幻读。对于当前读场景比如 SELECT ... FOR UPDATE、UPDATE、DELETEMySQL 通过间隙锁或临键锁来限制其他事务插入新记录从而解决幻读。这也是面试中最容易出彩的点。6. 锁机制与死锁排查6.1 行锁与表锁InnoDB 默认使用行级锁表级锁也可以在特定场景出现比如 DDL 语句或者查询没有走索引时。行锁是加在索引记录上的所以如果一条 update 语句的 where 条件没有走索引InnoDB 无法确定具体行就可能锁住更多记录甚至升级为表锁。这会导致并发性能急剧下降是生产中常见的性能隐患。基本的行锁有两种模式共享锁也叫读锁。多个事务可以同时持有共享锁但都不能修改数据。使用 SELECT ... LOCK IN SHARE MODE 或 SELECT ... FOR SHARE 加锁。排他锁也叫写锁。一个事务持有排他锁后其他事务不能加共享锁和排他锁。INSERT、UPDATE、DELETE 默认加排他锁SELECT ... FOR UPDATE 可以手动加排他锁。面试时尽量用自己的话说清楚共享锁就是“大家可以一起读但谁都不能写”排他锁就是“只有我能读写你们都不许动”。6.2 间隙锁与临键锁在 REPEATABLE READ 隔离级别下InnoDB 为了解决当前读的幻读问题引入了间隙锁和临键锁。间隙锁锁住的是一个范围区间而不是具体的记录。比如表中 id 有 1、5、10间隙锁可能锁住 (1,5) 这个区间这样其他事务就无法在这个区间插入 id3 的记录自然就不会出现幻读。临键锁是记录锁和间隙锁的组合锁住的是一段左开右闭的区间比如 (1,5]既锁住记录又锁住记录前面的间隙。要注意间隙锁会降低并发性能只在 REPEATABLE READ 及以上隔离级别生效。如果把隔离级别改成 READ COMMITTED间隙锁通常会失效MySQL 会使用其他机制控制并发。6.3 悲观锁与乐观锁面试中锁机制经常和“悲观锁、乐观锁”一起考。悲观锁在操作数据前先加锁认为别人一定会修改数据乐观锁则默认别人不会修改更新时再检查版本。悲观锁在 MySQL 中通过 SELECT ... FOR UPDATE 实现事务结束自动释放。使用时要特别注意加锁的查询条件必须走索引否则可能锁范围过大。乐观锁通常加一个 version 版本号字段更新时比较版本号UPDATE user SET age 26, version version 1 WHERE id 1 AND version 5;影响行数为 0 说明版本号不匹配更新失败由业务层重试或提示用户。6.4 死锁怎么排查死锁是指两个或多个事务互相等待对方持有的锁导致事务无法继续执行。InnoDB 会自动检测死锁并将一个事务回滚让另一个事务继续执行。面试中经常问“死锁怎么排查”。常见思路是查看最近一次死锁信息在 MySQL 命令行执行 SHOW ENGINE INNODB STATUS重点看 LATEST DETECTED DEADLOCK 部分。从输出中看两条事务各自持有什么锁、等待什么锁。找到死锁的根源通常是两个事务以不同顺序获取资源。比如事务 A 先更新 id1 再更新 id2事务 B 先更新 id2 再更新 id1两者就可能在 id1 和 id2 上互相等待。解决死锁的常见手段包括统一加锁顺序、缩小事务执行时间、减少大事务、让查询尽量走索引避免锁范围过大。7. SQL 优化与慢查询分析7.1 开启慢查询日志定位问题 SQL项目上线后出现接口变慢优先怀疑数据库慢查询。慢查询日志就是用来记录执行时间超过阈值的 SQL。在 MySQL 命令行中执行SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1; SHOW VARIABLES LIKE slow_query_log;也可以写入配置文件永久生效[mysqld] slow_query_log 1 slow_query_log_file /var/log/mysql/slow.log long_query_time 1 log_queries_not_using_indexes 1log_queries_not_using_indexes 表示把未使用索引的查询也记录到慢查询日志适合用来发现大量全表扫描 SQL。慢查询日志文件可以使用 mysqldumpslow 工具分析mysqldumpslow -s t -t 10 /var/log/mysql/slow.log这条命令的意思是按查询耗时排序显示耗时最长的前 10 条 SQL。7.2 使用 Explain 分析执行计划慢查询日志只是发现问题的入口定位到具体 SQL 后需要分析它为什么慢。最常用的方法是在 SQL 前面加 EXPLAIN。EXPLAIN SELECT * FROM order WHERE user_id 123;执行结果会展示这条 SQL 的执行计划重点关注几个字段字段含义type访问类型从好到差依次是 system、const、eq_ref、ref、range、index、ALLpossible_keys可能用到的索引key实际使用的索引rows预估扫描行数Extra额外信息比如 Using index、Using where、Using temporary、Using filesorttype 字段是重要参考。ALL 表示全表扫描index 表示扫描了整个索引树range 表示范围扫描ref 表示通过索引等值查询。type 为 ALL 或 index 的 SQL 通常是优化重点。Extra 字段中如果出现 Using filesort说明 SQL 需要额外的排序操作可能是 order by 的字段没有走索引如果出现 Using temporary说明查询过程中使用了临时表常见于 group by、distinct 或大数据量排序。7.3 一个优化实战示例假设发现一条慢查询SELECT * FROM order WHERE user_id 123 ORDER BY create_time DESC LIMIT 20;如果 order 表只有主键索引这条 SQL 的执行过程很可能是先通过 user_id 全表扫描找到所有该用户的订单再对 create_time 排序最后取前 20 条。数据量大时排序成本很高。优化方式建立一个联合索引。ALTER TABLE order ADD INDEX idx_user_create (user_id, create_time);加上索引后InnoDB 可以直接通过联合索引定位 user_id123 的记录而且 create_time 天然有序不需要额外 filesort性能明显提升。这条优化思路面试中经常考核心就是索引不光能加速 where 过滤还能让 order by 利用索引有序性避免排序。再补充几个常见优化点避免 SELECT *只查需要的字段减少回表和网络传输。分页查询使用 LIMIT 时深分页可能很慢比如 LIMIT 100000, 20可以通过子查询或记录上次最后一条 id 来优化。对频繁使用的查询条件合理设计联合索引避免为每个字段单独建索引。8. 高频 MySQL 面试题整理这一节把 Java 后端面试中最高频的 MySQL 面试题按模块整理出来每道题给出回答思路和核心得分点。建议先自己说一遍答案再看参考思路效果更好。8.1 基础与 SQL 类一条 select 语句的执行过程参考答案客户端连接 MySQL 后SQL 依次经过连接器、分析器、优化器、执行器最终调用存储引擎读取数据。MySQL 8.0 之前还有查询缓存8.0 之后已移除。得分点能说出分析器负责词法语法分析优化器负责选索引和决定连接顺序执行器负责调用存储引擎接口。truncate delete drop 有什么区别参考答案DELETE 是 DML可以带 WHERE逐行删除不释放表空间TRUNCATE 是 DDL清空整张表并释放存储空间不能加 WHEREDROP 是 DDL直接删除表结构。二者都可以手动删除数据但 DDL 操作隐式提交不可回滚。得分点事务中 DELETE 可以回滚TRUNCATE 不支持说到“隐式提交”会加分。WHERE 和 HAVING 有什么区别参考答案WHERE 在分组之前过滤不能使用聚合函数HAVING 在分组之后过滤可以使用聚合函数。WHERE 过滤条件不参与分组HAVING 通常和 GROUP BY 配合使用。内连接、左连接、右连接的区别参考答案内连接只返回两边都匹配的行左连接返回左表全部行右表没有匹配项时用 NULL 填充右连接相反。实际项目中左连接最常见。得分点能补充连接查询的执行顺序先笛卡尔积再过滤或者提到小表驱动大表的优化思想。什么是存储过程优缺点是什么参考答案存储过程是预编译的 SQL 集合可以封装复杂业务逻辑减少网络传输但数据库层承担业务逻辑会导致维护困难、不好调试。得分点指出在互联网项目中不推荐大量使用存储过程业务逻辑尽量放在应用层。8.2 索引与 SQL 优化类为什么 InnoDB 使用 B 树做索引参考答案B 树非叶子节点只存索引键树更矮减少磁盘 IO叶子节点通过链表连接范围查询高效叶子节点存主键值适合聚簇索引和二级索引结构。得分点能对比 B-Tree、Hash、红黑树的适用场景。什么是回表如何避免回表参考答案二级索引查到主键后再到聚簇索引查整行数据就是回表。避免回表的方法是覆盖索引也就是查询字段全部在二级索引中。得分点能说清楚覆盖索引的 Extra 是 Using index。联合索引的最左前缀原则是什么参考答案联合索引按最左边字段开始匹配查询条件必须包含最左边的列才能用索引。索引字段顺序设计要结合实际查询频率。得分点能解释为什么 MySQL 不直接跳过最左列使用索引。什么情况下索引会失效参考答案对索引列使用函数、隐式类型转换、LIKE 以 % 开头、OR 连接非索引列、不满足最左前缀原则等都可能让索引失效。最终是否失效要看优化器对成本的判断。得分点不把结论说死强调优化器会评估数据量和执行成本。如何优化一条慢查询 SQL参考答案先用 EXPLAIN 查看执行计划重点看 type、key、rows、Extra再检查是否有全表扫描、filesort、临时表根据查询条件建立合适的联合索引避免 SELECT *必要时改写 SQL。得分点回答里提到慢查询日志定位问题 SQL再用 EXPLAIN 分析形成完整排查链路。8.3 事务与锁类事务的 ACID 分别是怎么实现的参考答案原子性通过 undo log 实现回滚持久性通过 redo log 保证崩溃恢复隔离性通过锁和 MVCC 实现一致性由应用约束和数据库约束共同保证。得分点能提到 undo log 和 redo log而不是只背 ACID 四个单词。MySQL 默认隔离级别是什么参考答案MySQL InnoDB 默认隔离级别是 REPEATABLE READ和 Oracle 默认的 READ COMMITTED 不同。RR 下通过 MVCC 解决快照读的不可重复读和幻读通过间隙锁解决当前读的幻读。得分点能和 Oracle 默认隔离级别对比说明为什么 MySQL 选择 RR。脏读、不可重复读、幻读有什么区别参考答案脏读读到未提交数据不可重复读是同一行数据两次读取不一致幻读是结果集行数变化。脏读是隔离性最差的情况幻读最难理解。得分点各举一个小例子面试官会觉得理解到位。MVCC 解决了什么问题参考答案MVCC 让快照读不加锁就能实现一致性读取。RR 下通过复用一个 ReadView 解决不可重复读RC 下每次读取生成新 ReadView会出现不可重复读。得分点能说到 ReadView 就是事务快照理解版本链和可见性判断。select for update 是什么有什么注意事项参考答案它会对查询结果加排他锁当前事务提交或回滚后释放。使用时要确保 where 条件走索引否则可能锁过多记录影响并发性能。得分点提到悲观锁并意识到锁范围问题。悲观锁和乐观锁怎么实现参考答案悲观锁用 SELECT ... FOR UPDATE 加锁乐观锁用版本号机制更新时校验版本影响行数为 0 则更新失败。得分点提到乐观锁适合冲突较少的场景悲观锁适合写冲突较多的场景。8.4 架构与部署类主从复制是怎么实现的参考答案主库把数据变更写入 binlog从库通过 IO 线程拉取 binlog 并写入中继日志SQL 线程再回放中继日志实现数据同步。得分点能说出 binlog、中继日志、IO 线程、SQL 线程四个关键概念。什么是读写分离主要解决什么问题参考答案读写分离让读请求走从库、写请求走主库降低主库压力提升读扩展能力。但主从存在延迟读刚写入的数据可能读不到。得分点能主动提主从延迟问题并能说出延迟场景可以是读不到最新数据比如刚下单查订单列表。分库分表了解吗参考答案分库分表解决单库单表数据量过大导致的性能瓶颈常见方式有垂直拆分和水平拆分。水平分表后查询需要带上分片键否则会路由到所有表复杂度明显上升。得分点能说出分片键的重要性以及分页、分布式事务、跨库 join 是主要难点。缓存和数据库一致性怎么做参考答案常见方案是先更新数据库再删除缓存。如果缓存删除失败可以通过消息队列重试或延迟双删兜底。不要先更新缓存因为一旦数据库回滚缓存已经变了。得分点能提到删除缓存而不是更新缓存能提到重试机制。9. 面试回答话术与避坑清单9.1 回答结构结论先行再展开原理MySQL 面试题很多都有标准答案但面试官更希望听到结构清晰的表达。建议使用“结论先行 → 原理补充 → 场景举例”的结构。比如问“为什么使用 B 树”可以先说结论为了减少磁盘 IO 并支持高效范围查询。然后展开原理B 树非叶子节点不存数据树更矮一次查询 IO 次数更少叶子节点链表连接范围查询不用回上层节点。最后补一个例子InnoDB 主键索引叶子节点存整行数据二级索引叶子节点存主键回表过程也是基于这个结构。这样回答即使不是最优答案面试官也能清晰跟住你的思路。9.2 面试避坑清单准备 MySQL 面试时有几个常见问题值得注意只背结论不解释原理。比如知道“RR 能解决幻读”但说不清是 MVCC 解决快照读、间隙锁解决当前读容易被追问卡住。把索引失效说成绝对结论。索引是否失效和优化器、数据量、索引统计信息都有关系回答时留有余地更稳妥。混淆事务隔离级别。四个隔离级别和三个问题之间的对应关系要能快速默写。没有排查思路。问“SQL 很慢怎么办”不要只说“加索引”要说清楚先开慢查询日志、再用 Explain、再看执行计划结构。涉及 delete update 时安全意识不足。面试中遇到“删除数据”这类问题要主动提到 WHERE 条件、事务回滚、备份这会让面试官觉得你有生产环境经验。9.3 考前最后一天怎么复习最后一天不建议再刷大量新题而是把核心内容过一遍重点验证自己的表达是否流畅。可以先对着镜子或者录屏自问几个高频题比如“InnoDB 和 MyISAM 的区别”“一条 SQL 的执行过程”“Explain 中 type 的取值顺序”看能不能不卡壳说出来。然后在本地环境把索引失效场景、死锁复现、Explain 执行计划各跑一遍。比如建两张表开两个事务交叉更新同一条记录触发一次死锁再用 SHOW ENGINE INNODB STATUS 查看死锁输出。这个过程比背十道题都管用。最后翻一下自己项目里写过的复杂 SQL想一想为什么当初要这么写有没有优化空间。面试官问你项目经历时大概率会顺着项目里的表结构和 SQL 继续深挖提前准备比临场发挥更稳。把这些步骤做完再去面对 MySQL 面试题你已经不是停留在背答案而是能讲清楚原理和排查思路了。希望这篇 Java 面试 MySQL 复习笔记能帮你节省时间少走弯路。8 月准备面试时间不算多但抓住重点3 天足够把 MySQL 这条主线完整过一遍。