mysql hash分区不支持reorganize partition,因其散列函数与分区数强耦合;必须通过新建表、insert…select重散列、原子重命名完成分区数调整,且需评估数据倾斜度与性能影响。
alter table … reorganize partition 在 mysql hash 分区中不支持
mysql 的 hash 分区不支持直接用 reorganize partition 来增加分区数,执行会报错:error 1064 (42000): you have an error in your sql syntax 或更明确的提示:reorganize is not supported for hash/key partitions。这是因为 hash 分区依赖确定性散列函数(如 mod(unhex(sha2(col,256)), n)),分区数变更后原有行的散列结果必然改变,无法像 range/list 那样靠边界挪动来“重组织”。
所以别试 ALTER TABLE t REORGANIZE PARTITION p0,p1 INTO (PARTITION p0, PARTITION p1, PARTITION p2, PARTITION p3)——它根本解析不过。
唯一可行路径:新建表 + INSERT … SELECT + 原子替换
要让 HASH 分区数翻倍(比如从 4 → 8),本质是重建数据分布。必须走“导出-重建-切换”流程,且需确保业务可接受短时写入阻塞或使用双写方案。
- 先用
SHOW CREATE TABLE t备份原 DDL,把PARTITION BY HASH(col) PARTITIONS 4改成PARTITIONS 8 - 用新 DDL 创建空表
t_new,注意引擎、字符集、索引、约束全部对齐 - 执行
INSERT INTO t_new SELECT * FROM t—— 这步会按新分区数重新计算每行的MOD(hash(col), 8),完成数据重散列 - 在低峰期用
RENAME TABLE t TO t_old, t_new TO t原子切换(要求两张表同库)
如果表太大,INSERT ... SELECT 可能锁表太久,可分批加 LIMIT 和 WHERE 条件(但需保证主键/唯一键覆盖全量,避免漏数据)。
为什么不能只改元数据或跳过重散列?
有人想绕开数据搬运,比如直接 UPDATE mysql.partitions 表或用 mysqldump --tab 后手动改分区定义——这会导致严重不一致:
- 查询时优化器仍按旧分区数做路由,部分数据永远查不到
-
EXPLAIN PARTITIONS显示的分区名和实际物理文件不匹配,SELECT可能读到错误 .ibd 文件 - 后续
INSERT会按新规则写入,但老数据还在旧分区里,表逻辑分裂
MySQL 不提供“就地 rehash”能力,因为散列函数输出与分区数强耦合,没有中间态可过渡。
加倍后性能变化:吞吐可能降,延迟未必升
分区数翻倍不等于性能翻倍。实际效果取决于数据倾斜度和查询模式:
- 若原 HASH 函数本身均匀(如对
BIGINT主键取模),8 分区后并发写入吞吐通常提升;但若原字段存在大量重复值(如状态码只有 0/1),加倍后仍集中在 2 个物理分区,无效 - 单条
WHERE id = ?查询仍只打一个分区,延迟基本不变;但SELECT COUNT(*)需合并 8 个分区结果,总耗时可能略增 - 每个分区对应独立 .ibd 文件,文件句柄数、缓冲池压力同步上升,
innodb_buffer_pool_size不足时反而降低命中率
真正关键的是:加倍前先用 SELECT COUNT(*) GROUP BY MOD(HASH_FUNC(col), 4) 检查当前倾斜度,再决定是否值得加倍——多数时候,换更均匀的散列字段比盲目加分区更有效。










