那天面完试,小米坐在咖啡厅,望着窗外飘着细雨的街景,脑海里却还在回味刚刚面试官的问题。
“你能讲讲,在什么场景下该加索引吗?”
没错,又是老朋友——MySQL索引。
这个问题看起来简单,但真要答得全面,能答出亮点,其实没那么容易。今天我就结合自己这些年在项目中踩过的坑、学过的知识、面过的试,把关于索引使用场景这个问题,拆开来说个透!
面试故事一:为什么我们系统查得越来越慢?
小米第一次遇到这个问题,是在一家做线上商城的创业公司。
有天产品经理跑过来:“小米,我们后台订单页面越来越卡,是不是数据库出问题了?”
小米一查日志,一条 SQL 执行了 8 秒!
SQL 长这样:

orders 表数据已经超过 500 万了,字段上没有任何索引,这种 全表扫描 的代价可想而知。
于是小米加了一个联合索引:

SQL 执行时间立刻从 8 秒降到 0.02 秒。
从那天开始,小米深刻理解了第一个场景:
场景一:WHERE 条件高频查询字段,必须加索引。
只要某个字段经常出现在查询条件里,它就值得一个索引。就像你经常找一位老朋友,当然要把他的手机号保存在通讯录里。
面试故事二:排序也会拖慢系统?!
又一个项目,小米帮客户开发一个日志平台。用户点开页面后,可以看到最近100条操作日志,按时间倒序排列。
但用户一多,页面经常加载超时。
SQL 是这样的:

logs 表有千万级数据,但 create_time 没加索引!
数据库想倒序找100条最新记录,就必须扫一遍全表再排序,性能堪忧。
加了索引后:
加载速度立刻飞起!
场景二:ORDER BY 排序字段也要加索引,尤其配合 LIMIT 使用时。
特别注意,排序字段的顺序要和实际的排序一致,加 DESC 不加 DESC,结果大不同。
面试故事三:你以为联合索引的顺序无所谓?
那天面试,小米问了一个学弟:
“你觉得联合索引 user_id, create_time 和 create_time, user_id 一样吗?”
学弟自信满满:“不都包含这两个字段嘛,能有啥区别?”
小米笑了。
我们线上有个表 user_actions,某天业务要查询:
如果索引是:

不好意思,user_id 排在第二位,用不上索引前缀,性能几乎和全表扫描差不多。
而如果换成:
效果直接起飞!
场景三:联合索引要考虑字段的使用顺序,最常出现在 WHERE 里的字段要靠前。
我们说索引是“左前缀匹配”,不是说谁重要就放前面,而是谁用得多、过滤性强就放前面!
面试故事四:别小看覆盖索引的威力!
还有一次优化经历让小米印象特别深。
有个用户列表页,SQL 是:
原来 status 字段是有索引的,但执行计划仍显示回表操作。
后来我们加了一个 联合索引:

结果查询快了两倍!
为啥?
因为原来虽然 status 有索引,但 name 和 email 不在索引里,数据库还得去主键索引“回表”取数据。而加了联合索引后,查询的数据都在索引里,直接返回,零成本回表,这叫覆盖索引。
场景四:频繁查询的字段可以组成覆盖索引,减少回表操作。
适合 OLAP 查询,特别是列表页展示。
面试故事五:别乱加索引!那是把双刃剑!
有次我们做数据库健康检查,发现一个表有 10 个索引!
更夸张的是,有两个几乎一样的索引:
后者已经覆盖前者,前者就是个累赘。而且写入时,每一条 INSERT、UPDATE 都要更新所有索引!
场景五:不是所有字段都要加索引,写多读少的场景尤其要谨慎。
索引是为了提高“读”的性能,牺牲的是“写”的性能和空间。
所以业务量大、读写比例高的场景,比如订单写入、日志插入,索引数量要特别小心。
小米的思考:面试时如何讲得更出彩?
讲到这里,如果你是在面试中回答这个问题,小米建议可以这样组织答案:
- 按照使用场景分类:where 条件、排序、覆盖索引、联合索引、避免冗余索引等;
- 配合项目经历举例子:面试官听故事会比听理论更有印象;
- 适当讲些原理支撑:比如“索引是B+树结构”、“回表代价”等;
- 不要过度炫技:讲得太深会适得其反,视对方水平而定。
尾声
小米面试走出来,天已经放晴了。
技术问题有时就像这场雨,看起来复杂,但只要你沉下心来分析场景,总能找出晴朗的那一面。
今天这篇分享,希望能帮你在面试时,把“索引使用场景”这个老问题,讲出新故事!
如果你也有有趣的 MySQL 优化故事,欢迎留言告诉小米,我们一起“索引”更高的技术之路!
END
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!

被折叠的 条评论
为什么被折叠?



