2025年Java面试宝典新鲜出炉!点击领取 (提取码: 9b3g)

二、真实面试题:订单表查询为什么会变慢?
上周面试时被问到一道MySQL高频题:"公司订单表数据量到百万级,根据手机号查询订单突然变慢,可能是什么原因?"
这类问题考察的核心就是MySQL回表现象。很多候选人知道回表的概念,但结合业务场景分析时往往抓不住重点。我们拆解下这个案例的解决思路:
2.1 执行计划里的秘密
假设订单表结构如下:
CREATE TABLE orders (
id INT PRIMARY KEY,
phone VARCHAR(11),
product_id INT,
create_time DATETIME
);
当执行SELECT * FROM orders WHERE phone='13512345678'时:
- 如果只有主键索引,会全表扫描,效率低下
- 如果给phone字段加普通索引,会先走索引找到主键id
- 回表操作:根据主键id回主键索引树取完整数据
这里有个关键细节:当select需要所有字段时(select *),即使phone有索引,MySQL也必须回表查询。而回表会产生大量随机IO,数据量大时就会成为性能瓶颈。

2.2 回表优化三板斧
在真实项目中,可以这样优化:
方案一:覆盖索引优化 将查询字段和条件字段都包含在索引中:
ALTER TABLE orders ADD INDEX idx_phone_product(phone, product_id);
这时执行SELECT phone, product_id FROM orders WHERE phone='...',直接通过索引就能拿到数据,无需回表
方案二:主键复用策略 如果业务允许,可以把手机号设计成主键的一部分,比如:
CREATE TABLE orders (
id VARCHAR(20) PRIMARY KEY, -- 格式:手机号_时间戳
phone VARCHAR(11),
...
);
这样通过phone前缀查询时可以直接利用主键索引
方案三:读写分离架构 针对海量数据场景,将历史订单归档到历史表,当前订单保留在热表。查询时根据时间范围选择对应表
2.3 高频追问与应对技巧
面试官可能会层层追问:
-
"覆盖索引失效的场景有哪些?"
- 当查询列包含非索引字段时
- 索引列使用了函数或表达式时
-
"为什么建议使用自增主键?"
- 避免页分裂带来的性能损耗
- 顺序写入对机械硬盘更友好
-
"如何判断是否发生回表?"
- 看执行计划的Extra字段:
- Using index:使用覆盖索引
- NULL:需要回表
- 看执行计划的Extra字段:

需要面试题库的小伙们注意啦,通过**面试鸭返利网**购买会员可享25元返利!现在领取2025年Java面试宝典提前备战金三银四。
三、避坑指南:回表与索引取舍
实际开发中要警惕两个极端:
- 盲目添加联合索引导致索引冗余
- 为了规避回表使用超大宽表
建议通过慢查询日志+执行计划分析定期优化索引。遇到分页查询优化时,可以配合延迟关联技巧:
SELECT * FROM orders
INNER JOIN (
SELECT id FROM orders
WHERE phone='13512345678'
LIMIT 100000,10
) AS tmp USING(id);
理解回表机制后,很多SQL优化问题都会迎刃而解。比如为什么阿里开发规约建议单表索引数不超过5个?因为每个额外索引都会增加写操作成本,需要权衡查询性能与存储开销。


