第4章 数据库性能调优面试题:SQL优化、索引设计、分库分表、读写分离高频问答

本章核心逻辑:数据库调优面试回答应遵循“先诊断、后优化、再分治”的路径。从单表SQL索引优化,到读写分离缓解读压力,再到分库分表突破写瓶颈,逐层递进。
数据库性能调优 SQL优化 索引设计 读写分离 分库分表 慢SQL·覆盖索引 联合索引·最左匹配 主从延迟·强制读主 分片键·跨分片事务 回答原则:先单表 → 再读写分离 → 最后分库分表

面试问答卡片

📌 问题1:一条慢SQL怎么排查和优化?

面试官考察点:是否掌握排查工具、优化思路、执行计划分析。

回答框架:1)使用 EXPLAIN 查看执行计划(type、rows、Extra);2)检查是否走全表扫描,分析索引使用情况;3)根据索引覆盖、减少回表、避免 SELECT *、限制扫描行数等优化。

示例回答:先用 EXPLAIN 发现该查询 type = ALL,无索引。检查关联字段后发现 where 条件列未建立索引,为支付流水号加唯一索引后 type 变为 ref,响应从 2s 降到 10ms。

可能追问:filesort 如何优化?联合索引最左前缀失效场景?Using temporary 怎么解决?

⚠️ 避坑提醒:不要只回答“加索引”,要结合业务说明加什么类型的索引;避免索引冗余导致写入变慢。

📌 问题2:支付流水表每天几千万数据,怎么设计索引?

面试官考察点:联合索引设计、索引选择性、避免索引失效。

回答框架:1)确定高频查询条件(商户ID、交易时间、订单状态);2)建立联合索引(商户ID + 交易时间 + 状态);3)考虑覆盖索引减少回表;4)定期清理历史数据或归档。

示例回答:支付流水表核心查询是“按商户查当天订单”。建联合索引 (merchant_id, create_time),状态字段选择性低不适合单独做索引,但可作为右缀加入。对于超大表配合分区分表。

可能追问:为什么状态字段不适合单独索引?IN 查询会走索引吗?order by 和索引顺序的关系?

⚠️ 避坑提醒:不要仅按业务直觉建索引,需关注索引选择性(distinct/总行数);避免在索引列上使用函数(DATE())导致失效。

📌 问题3:什么场景下需要做分库分表?读写分离怎么实现?

面试官考察点:架构演进能力、分片策略、主从延迟处理。

回答框架:1)单表数据超千万且索引无法满足;2)分片键选择业务相关字段(如用户ID、商户ID);3)读写分离通过主库写、从库读,中间件配置(如 ShardingSphere、MyCat);4)解决主从延迟:强制读主、延迟阈值、缓存补偿。

示例回答:支付流水表日均500万行,单表超1亿后写入并发受限。采用商户ID取模分8库,每库再按月分表。读写分离:写操作走主库,读操作走从库,对实时性要求高的查询强制走主库。

可能追问:分库后跨库查询怎么处理?全局ID生成?分库分表后如何扩容?

⚠️ 避坑提醒:避免过早分库分表增加复杂度;分片键一旦确定很难修改;跨分片事务尽量规避或弱化。

项目案例实战模板

🚀 项目名称:支付结算系统流水库性能优化

业务背景每日订单量超2000万,高峰QPS 5万,数据库成为瓶颈,订单查询超时严重。
规模指标单表数据量超3亿行;写入TPS 8000;读延迟P99 > 2s;MySQL 8.0 单机。
技术栈MySQL 8.0 + MyBatis + ShardingSphere 5.x + Redis 缓存 + Canal 同步。
核心难点① 分片键选商户ID导致热点商户单库压力大;② 按日分区后跨月查询性能差;③ 主从延迟30秒导致对账数据不一致。

面试高频追问:

  • 热点商户怎么解决?(商户ID+时间字段二次分片,或单独缓存热数据)
  • 跨月/跨年查询怎么做?(使用ES或ClickHouse做聚合查询,MySQL只保留近期数据)
  • 主从延迟怎么保证对账准确性?(对账采用双主库 + 最终一致性校验 + 离线补偿)
  • 分库后分布式事务怎么处理?(使用本地消息表 + 定时任务补偿,避免强XA)
  • 扩容时怎么不停机迁移?(双写 + 增量同步 + 灰度切流)

可迁移回答话术:

“在支付场景中,我们优先通过索引优化和读写分离满足业务增长,当单表数据量超过1亿且索引无法支撑时,才引入分库分表。分片键选择业务稳定性最高的商户ID,并配合二级时间字段避免数据倾斜。针对热点问题,通过缓存和异步分流来缓解,不盲目增加分片数。”
💡 面试加分技巧:回答数据库调优时,主动提及“监控指标”(慢查询日志、QPS、连接数)和“压测验证”,体现工程闭环思维。