数据库容量规划与管理是MySQL设计中极易被忽视却影响深远的环节。不少系统上线初期跑得顺畅,半年后随着数据堆积出现慢查询、主从延迟,根本原因常是建表时未预估增长量。技术同学应在需求评审阶段就介入,结合业务单量推算存储规模,并落实一套可落地的设计规约。
一、为什么设计阶段必须做容量规划
很多团队把容量规划等同于运维侧的硬盘扩容,这是典型误区。MySQL的瓶颈不止在磁盘,更在内存命中率与索引树高度。一张原本预计存百万数据的表,若业务爆发涨到五千万,即使加SSD也可能因buffer pool装不下热数据而频繁换页。
从原理看,InnoDB的B+树索引层数随记录数对数增长,但单页空间固定。当二级索引体积超过内存可用缓存,随机读会落到磁盘。设计期通过估算行大小与日增量,可提前判断何时该分表或归档,而不是等CPU告警才动手。这种前移动作能省去后期在线DDL的风险窗口。
二、字段与类型选型的规约要点
遵循最小化存储原则,能直接降低容量压力。例如订单号若为纯数字,用<bigint>比<varchar(32)>省空间且比较更快;时间戳用<datetime>或<timestamp>而非字符串。下面是建表时常见的错误与正确写法对比。
-- 不推荐:用varchar存数字ID,浪费空间且索引效率低 CREATE TABLE order_bad ( id varchar(20) NOT NULL, amount varchar(10), PRIMARY KEY (id) ) ENGINE=InnoDB; -- 推荐:使用bigint和decimal,紧凑且利于计算 CREATE TABLE order_good ( id bigint NOT NULL, amount decimal(10,2), PRIMARY KEY (id) ) ENGINE=InnoDB;
上述改动在千万级数据下可缩减约三成表空间,从库同步的binlog体积也同步下降。规约中应明确禁止用字符串存数值、禁止给频繁更新的列建过多索引,避免写放大。
另外,TEXT与BLOB类型应隔离到扩展表。主表只留检索必需的字段,既缩小聚簇索引,也提升备份效率。若业务必须存长文本,可考虑外部对象存储,库内仅记引用地址。
三、分库分表与归档阈值设计
单实例单表建议控制在两千万行以内,超出后维护成本陡增。技术同学需根据日产生量反推:若日均百万流水,半年即一点八亿,就应在设计初选定分表键,如按用户ID哈希或按时间按月分表。
-- 按月份分表的命名与路由示例(应用层逻辑) -- 订单表拆分为 order_202401, order_202402 ... SELECT * FROM order_202402 WHERE user_id = 123; -- 归档旧数据的简单存储过程片段 INSERT INTO order_archive SELECT * FROM order_202301 WHERE create_time < '2023-02-01'; DELETE FROM order_202301 WHERE create_time < '2023-02-01';
分表虽解容量忧,但跨表查询变复杂。规约里要写清分片算法与唯一ID生成方式,避免后期为统计而扫全部分片。同时设定冷数据归档任务,将一年前数据迁至廉价存储,保证主库轻量。
容量规划不是一次性文档,而应随业务复盘调整。每季度回顾实际增量与预估偏差,动态修正分表节奏,才能让MySQL在多变场景中持续稳定。
四、索引与冗余的控制规约
索引是双刃剑,过多索引拖慢写入并占空间。设计时应要求每个索引都有查询覆盖说明,杜绝为未知需求建联合索引。利用<explain>在测试环境验证执行计划,确认索引命中。
冗余索引如(a,b)与(a)并存,应删掉后者。规约可规定上线前用pt-duplicate-key-checker类工具扫描。合理的索引宽度也关键,长字段前缀索引长度需评估选择性,避免盲目用全字段建索引。
| 规约项 | 推荐做法 | 禁止做法 |
|---|---|---|
| 主键类型 | 自增bigint | uuid字符串 |
| 单表行数 | 小于2000万 | 无上限增长 |
| 索引数量 | 不超过5个 | 随意添加 |
把上述条目写成团队MySQL设计评审清单,能有效减少容量事故。技术同学照此约束建模,系统扩展性会明显提升。