面试通关特训营第三天 ✅
2024 - 12 - 26
大家好,我是正在努力掌握 MySQL 知识的技术搬砖人 K.N。
昨天刷了三道 B+ 树的问题,今天早上工作的时候又不断在写前端相关的东西,今天继续进行三道 MySQL ,突然感觉自己像是在两个完全不同的战场来回穿梭,不过学习 MySQL 的乐趣还是挺多的,尤其是研究索引和优化时,真的感觉在探索性能的极限。
今天面试特训营的三道题目,主题依旧围绕 MySQL 的索引优化:
1)MySQL 中的回表是什么?
2)MySQL 中使用索引一定有效吗?如何排查索引效果?
3)在 MySQL 中建索引时需要注意哪些事项?
以下是我的学习心得,有错误的话请各位大神多多指点!
MySQL 中的回表是什么?
回表其实是 MySQL 查询过程中的一种现象,通俗点说,就是在用二级索引查询时,因为二级索引只存储键值和主键,没法直接拿到完整数据,需要通过主键再次查询聚簇索引来获取数据。
举个例子,假设有一张用户表 user,有一个二级索引 email。当执行以下语句时:
▼tsx复制代码SELECT name FROM user WHERE email = 'test@example.com'
- MySQL 先通过 email 索引找到对应的主键值;
- 然后再根据主键去聚簇索引中查找完整的行数据,获取 name 字段。
这个“先查索引,再回到聚簇索引”的过程就是回表。它在小数据量时影响不明显,但在大表查询或高频次查询中,会带来额外的性能消耗。解决回表问题的一个常见方法是使用覆盖索引(即查询字段全在索引里),这样可以直接通过二级索引返回结果,避免回表。
MySQL 中使用索引一定有效吗?如何排查索引效果?
索引并不是万能的,有时候它甚至可能不被使用或者导致性能下降。常见的索引失效场景包括:
- 条件不符合最左前缀原则,比如联合索引 (a, b),查询时跳过了 a;
- 使用了函数或表达式,例如 WHERE LEFT(name, 3) = 'abc';
- 对索引列做了隐式类型转换,比如 WHERE age = '18',而 age 是一个整数;
- 查询条件范围过大,比如 WHERE age > 100;
- 查询数据量太大时,MySQL 可能认为全表扫描更划算。
要排查索引效果,可以使用 EXPLAIN 分析执行计划。比如:
▼plain复制代码EXPLAIN SELECT name FROM user WHERE email = 'test@example.com';
重点关注 key、rows 和 Extra。如果 Extra 显示 Using where 或 Using filesort,说明查询性能可能存在问题。
另外,还可以用 SHOW STATUS LIKE 'Handler%' 查看查询过程中 MySQL 的索引使用情况。例如 Handler_read_key 表示通过索引读取的次数,Handler_read_rnd_next 表示全表扫描的次数。通过对比这些值,可以评估索引是否高效。
在 MySQL 中建索引时需要注意哪些事项?
建索引是一门艺术,做好了可以大幅提升性能,没做好可能白白浪费存储和资源。总结下来,有几个关键点需要注意:
- 根据查询需求设计索引:不要盲目创建索引,应该结合查询频率和条件来设计。比如经常用 WHERE status = ?,就需要给 status 建索引。
- 选择合适的字段顺序:联合索引 (a, b) 一定要优先把查询中使用最频繁的字段放在前面,比如 a 如果比 b 更常用于筛选,就让它排第一。
- 避免为低选择性字段建索引:比如 gender 这种只有两三个值的字段,建索引的效果很差,因为过滤效率低。
- 控制索引数量:索引会占用额外的存储空间,同时会影响插入、更新和删除操作的性能。一般来说,尽量只建最必要的索引。
- 考虑覆盖索引:如果查询的字段都能通过索引返回结果,避免回表,可以显著提高查询效率。
- 避免重复和冗余索引:比如同时建了 (a) 和 (a, b) 两个索引,其实前者是多余的。
建索引的时候,多用 EXPLAIN 和慢查询日志分析查询性能,确保索引是有价值的,而不是增加额外负担。
