联合索引 (a,b,c) 能否满足 where b=1 and c=2?给出解释与改写方案

解读

  1. 面试官想确认你对 MySQL 索引最左前缀原则的掌握深度,以及能否把理论快速映射到性能测试场景。
  2. 性能测试工程师不仅要“能跑脚本”,更要能预判索引失效带来的 RT 突增、TPS 陡降,提前在测试模型里埋点监控。
  3. 国内互联网面试节奏快,回答必须“结论先行 + 原理一句话 + 测试验证思路 + 改写方案”,否则会被打断。

知识点

  1. 最左前缀原则:B+ 树复合索引按声明顺序排序,查询必须从最左列开始连续匹配,才能走索引范围扫描。
  2. 跳过左边列导致索引无法用于“排序 + 过滤”,优化器只能选择全表/全索引扫描或生成临时表。
  3. 性能测试视角:索引失效直接体现为 explain 中 type=ALL、rows 陡增、CPU/iowait 上涨、99 线 RT 劣化。
  4. 国内主流版本 5.7/8.0 均不支持 skip scan 对 (b,c) 的优化,除非 8.0.13+ 且优化器主动选择,生产环境多数关闭。
  5. 改写方案需兼顾线上灰度风险与测试回归成本,性能测试要给出量化对比基线(QPS、RT、CPU、锁等待)。

答案

结论:不能充分利用联合索引 (a,b,c) 完成 where b=1 and c=2,会退化为全表或全索引扫描,性能测试视角即为 RT 突增、TPS 掉底。
原理:缺少最左列 a 的等值条件,优化器无法沿着 B+ 树有序节点做范围裁剪。
测试验证:

  1. explain format=json 查看 type=ALL,rows≈全表;
  2. 压测 500 并发,持续 15 min,记录 99 RT 与 CPU;
  3. 添加对照实验:新建 (b,c) 或 (b,c,a) 索引,同样负载对比 RT 下降比例、TPS 提升幅度。
    改写方案(按国内可灰度执行顺序):
  4. 最轻量:新建冗余索引 (b,c) ,占磁盘但生效最快;性能测试需评估写入放大(iostat 观察 w/s、util)。
  5. 若表已分区且 b 为低频过滤,可改写成 union 拆分:
    select … where a=常数1 and b=1 and c=2
    union
    select … where a=常数2 and b=1 and c=2
    利用 (a,b,c) 索引,但需保证 a 的枚举值极少,否则 RT 反而爆炸;性能测试需构造边界值验证。
  6. 覆盖索引+延迟回表:select 列仅包含 (b,c,id) ,强制 icp 条件下推,虽仍全索引扫描,但减少回表 IO;测试对比逻辑读(innodb_buffer_pool_reads)。
  7. 业务层妥协:把 b=1 and c=2 结果缓存到 Redis,降低 80% 流量,性能测试需验证缓存穿透时数据库兜底能力。

拓展思考

  1. 作为性能测试,如何量化“索引失效”对 SLA 的影响?
    答:在压测模型里把这条 SQL 单独拎出来做权重 20% 的混合场景,对比基线 TPS 下降是否触碰业务方 95% 红线,若触碰则必须推动上线前加索引。
  2. 国内大表加索引怕锁表,性能测试如何给出“低风险窗口”?
    答:用 gh-ost 或 pt-osc 做影子索引,测试阶段先克隆 1/10 数据量验证拷贝速率、主从延迟,再给出凌晨 2-4 点低峰窗口,要求延迟 <1s 切流。
  3. 如果业务方拒绝加索引,性能测试如何兜底?
    答:在测试报告里明确“高并发下 99 RT 超 1s 概率 5%,建议降级开关 + 限流阈值 200 QPS”,并给出熔断自动化脚本,让运维在监控告警时一键降级,防止生产雪崩。