MySQL分区由服务端SQL定义,非Linux配置;需SHOW VARIABLES LIKE 'have_partitioning'确认为YES,且分区列必须包含在主键或唯一索引中,否则报错1503。

MySQL 分区表不是靠 Linux 系统配置的,而是由 MySQL 服务端在建表或修改表结构时通过 PARTITION BY 语法定义的。Linux 只负责提供运行环境(如磁盘空间、文件权限、my.cnf 配置路径),真正启用分区的关键在 MySQL 内部配置和 SQL 操作。
确认 MySQL 已启用分区功能
分区不是默认开启的插件,必须检查 MySQL 是否支持且已加载:
- 执行
SHOW VARIABLES LIKE 'have_partitioning';,返回值必须是YES,不是DISABLED或空 - 若为
NO或报错,说明你的 MySQL 编译时未启用分区支持(常见于某些精简版或旧版 MariaDB) - 5.1+ 官方 MySQL 二进制包默认开启,但部分 Linux 发行版打包时可能裁剪;CentOS 7 的
mysql-community-server通常没问题,Ubuntu 的mysql-server也基本支持 - 无需手动改 Linux 内核参数或挂载选项——分区完全在 InnoDB 层实现,与 ext4/xfs 文件系统无关
建表时指定分区规则(以 RANGE 时间分区为例)
这是最常用也最容易出错的环节。核心限制:分区列必须包含在主键或唯一索引中。
- 错误写法:
PRIMARY KEY (id)+PARTITION BY RANGE (TO_DAYS(log_time))→ 报错ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function - 正确写法:把
log_time加进主键,例如PRIMARY KEY (id, log_time),或单独建UNIQUE KEY (log_time, id) - 推荐用
TO_DAYS()而非YEAR()或MONTH():避免跨年/跨月数据误入同一分区,且支持日期范围查询下推 - 示例语句:
CREATE TABLE logs ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, log_time DATETIME NOT NULL, content TEXT, PRIMARY KEY (id, log_time) ) ENGINE=InnoDB PARTITION BY RANGE (TO_DAYS(log_time)) ( PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')), PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01')), PARTITION p_future VALUES LESS THAN MAXVALUE );
动态添加新分区(避免手动 ALTER)
生产环境不能等分区满了才加,得提前预设或自动创建。Linux 上可配合 MySQL 事件调度器 + 存储过程实现:
- 先确保事件调度器开启:
SET GLOBAL event_scheduler = ON;,并写入/etc/my.cnf的[mysqld]段落:event_scheduler=ON - 存储过程里用
ALTER TABLE ... ADD PARTITION,注意VALUES LESS THAN必须严格递增,不能重复或倒序 - 容易踩的坑:
DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01')生成的字符串需转为日期再套TO_DAYS(),否则会因类型不匹配导致 SQL 执行失败 - 别在高峰期执行
ADD PARTITION:DDL 会锁全表(即使分区表,新增分区仍需元数据锁)
验证分区是否生效 & 查看物理位置
建完不等于跑起来,得确认 MySQL 真按分区存了数据,且 Linux 文件系统能承载:
- 查分区使用情况:
EXPLAIN PARTITIONS SELECT * FROM logs WHERE log_time >= '2026-05-01';,输出的partitions列应只显示匹配的分区名(如p202605),不是NULL或全部分区 - InnoDB 分区表每个分区对应一个独立
.ibd文件,路径在 MySQL 数据目录下,例如/var/lib/mysql/your_db/logs#P#p202601.ibd—— 这个#P#是 MySQL 自动加的,Linux ls 能看见,但不能直接操作这些文件 - 检查磁盘空间:分区文件分散在同一个文件系统,如果单个分区超 100GB,而所在磁盘只剩 20GB,后续 INSERT 会报
ERROR 1030 (HY000): Got error 28 from storage engine(磁盘满),和普通表一样要监控 - 不要用
df -h看单个分区文件大小来估算总容量——ls -lh显示的是稀疏文件逻辑大小,实际占用看du -sh
最关键的遗漏点:很多人以为加了 PARTITION BY 就万事大吉,但只要查询条件没带上分区键(比如 WHERE status = 1 而不是 log_time),MySQL 仍会扫描所有分区,性能反而更差。分区不是银弹,它只对含分区键的查询生效。











