MySQL 大表优化

这篇是我基于一篇早期讨论内容整理的实践笔记,重点放在“遇到大表性能问题时,按什么顺序处理更稳妥”。

原讨论链接: https://www.zhihu.com/question/19719997/answer/81930332

处理顺序(先低成本,再高成本)

大多数系统都适合按以下顺序推进,避免一上来就分库分表:

  1. 先优化 SQL 和索引。
  2. 再加缓存(如 Redis),减少数据库读压力。
  3. 再做读写分离(主从)或副本扩展。
  4. 再评估分区表(前提是查询条件能命中分区键)。
  5. 再做垂直拆分(按业务域拆库)。
  6. 最后才是水平拆分(分库分表 + 路由)。

核心原因是:越往后改造成本越高,业务侵入越强,回退也越困难。

SQL 与索引是第一优先级

很多慢库问题并不是“数据库不行”,而是这三件事没有做透:

  1. SQL 写法没有针对索引设计。
  2. 索引数量过多或选择不对,拖慢写入。
  3. 优化单条 SQL 时忽略了全局负载,出现“局部变快、整体变慢”。

建议先做这套最小闭环:

  1. 用慢查询日志找 Top N SQL。
  2. 用 EXPLAIN 验证执行计划。
  3. 在压测环境对比“改前/改后”整体 RT、QPS、CPU、IO。

分区、垂直拆分、水平拆分怎么选

分区表

适合“时间范围明显、查询常带分区键”的表。优点是对业务代码相对透明;缺点是分区命中差时容易扫全分区。

垂直拆分

适合按业务域解耦,把不同模块压力拆到不同库。它能降低单实例总压力,但不能解决单表本身太大的问题。

水平拆分

适合单表已达到容量或吞吐瓶颈。收益大,但代价也最大:

  1. 需要稳定的分片键设计。
  2. SQL 路由、聚合查询、跨分片事务复杂度明显上升。
  3. 常常需要改表结构、做冗余字段、改应用代码。

关于 InnoDB 与 MyISAM 的取舍

在当前线上系统里,绝大多数场景优先 InnoDB:

  1. 支持事务与行级锁。
  2. 并发写能力更稳。
  3. 故障恢复能力更好。

MyISAM 在某些纯读场景可能有优势,但在写多或读写混合场景里,通常不是优先选项。

实战建议

如果你正在处理“大表 + 写入变慢”,建议按下面清单落地:

  1. 先确认瓶颈在 SQL、锁、IO、还是连接池。
  2. 明确读写模型(读多写少、写多读少、时间范围查询比例)。
  3. 先完成 SQL/索引/缓存优化,再决定是否拆分。
  4. 如果进入拆分阶段,先做垂直拆分,再做水平拆分。

延伸阅读