答案是:先定位慢查询,再用explain分析执行计划,识别索引失效(如create_time范围查询在联合索引中位置不当),最后调整索引顺序为(user_id, delete_flag, create_time)并验证优化效果。

面试官问“MySQL SQL 优化”,不是想听概念复述,而是看你有没有真实排查过慢查询、能不能一眼识别索引失效点、会不会用 EXPLAIN 做决策。下面用一个高频实战案例讲清楚从问题暴露到落地优化的全过程。
一、典型慢查询场景还原
某电商后台接口“查用户近三个月已支付订单”,SQL长这样:
SELECT id, order_no, order_amount, create_time FROM tb_order WHERE user_id = 10086 AND delete_flag = 0 AND create_time >= '2025-01-01' AND create_time
表有 500 万数据,响应超 5 秒。执行计划显示 type=ALL,rows=5023412,明显全表扫描。
二、三步定位根因(面试必答逻辑)
不用猜,按顺序检查:
- 看 WHERE 条件字段是否有索引:user_id 有单列索引 idx_user_id,但其他字段 delete_flag、pay_status、create_time 都没索引
- 看条件组合是否触发最左前缀:当前只靠 idx_user_id,后面全是过滤,无法跳过扫描;且 create_time 是范围查询,它右边的 pay_status 在联合索引中也无法生效
- 看执行计划 Extra 字段:出现 Using where; Using filesort,说明既要回表、又要临时排序,双重开销
三、优化动作与原理说明
不是加个索引就完事,要对症下药:
- 建联合索引:KEY idx_user_del_pay_ct (user_id, delete_flag, pay_status, create_time) 顺序按“等值 → 范围”排列:user_id = ?、delete_flag = ?、pay_status = ? 全是等值,create_time 才是范围,保证前三列都能走索引
- 确认覆盖查询:SELECT 只要 id、order_no 等非索引字段?不行 —— 加上 order_no 到索引里变成覆盖索引更优 改为:KEY idx_user_del_pay_ct_cover (user_id, delete_flag, pay_status, create_time, order_no, order_amount),避免回表
- 注意隐式类型转换风险:如果代码里传的是字符串 user_id='10086',而字段是 bigint,MySQL 会自动转,但某些版本可能影响索引选择,统一用数字类型传参
四、验证效果与面试加分点
优化后执行计划应变为:
- type=range(不再是 ALL)
- key=idx_user_del_pay_ct_cover(明确命中索引)
- Extra=Using index(说明是覆盖索引,无需回表)
- rows 从 500 万降到 2 万以内(取决于 user_id 下满足条件的数据量)
补充一句:“上线前我会在从库或影子库压测,对比 QPS 和平均延迟;同时监控 slow log 是否还有同类语句漏网。”——体现工程闭环意识。










