mysql不支持用alter table修改分区表的partition by子句,只能通过重建表或reorganize partition调整单个分区;增删分区需遵循严格规则,exchange partition要求结构完全一致且交换表必须为空并去分区化。

ALTER TABLE对分区表的支持有限,不能直接修改PARTITION BY子句
MySQL不允许用ALTER TABLE ... PARTITION BY重定义分区逻辑——比如把RANGE改成LIST,或调整分区键字段。执行这类语句会报错:ERROR 1486 (HY000): Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed,哪怕语法看似合法。本质是分区函数一旦建表就固化,引擎不支持运行时重写分区规则。
可行路径只有两个:重建表(用CREATE TABLE ... LIKE + INSERT ... SELECT + DROP/RENAME)或逐个调整现有分区(增删/重定义单个分区)。前者停机时间长但彻底;后者快但能力受限。
添加、删除或重定义单个分区要用REORGANIZE PARTITION
这是最常被误用的操作。比如想为RANGE分区新增一个高值区间,不能用ADD PARTITION直接加——必须先用REORGANIZE PARTITION合并旧分区再拆分。典型场景:
- 原分区:
P0 VALUES LESS THAN (100), P1 VALUES LESS THAN (200) - 想加
P2 VALUES LESS THAN (300):得先REORGANIZE PARTITION P1 INTO (P1 VALUES LESS THAN (200), P2 VALUES LESS THAN (300)) - 删分区?
DROP PARTITION只允许删LIST或RANGE的末尾分区(P1可删,P0不行),否则也得靠REORGANIZE先把目标分区合并进相邻分区再删
注意:REORGANIZE会锁表并拷贝数据,大表操作前务必在低峰期执行,且确认tmpdir空间足够。
修改分区字段类型或加索引,和普通表一样但有隐含风险
ALTER TABLE ... MODIFY COLUMN或ADD INDEX语法上没区别,但分区表下容易触发意外行为:
- 修改分区键字段类型(如
INT→BIGINT)可能失败,因为引擎需校验所有分区数据是否兼容新类型,遇到溢出值直接中断 - 给非分区键字段加索引,MySQL会为每个分区单独建索引文件,总索引大小 = 单分区索引 × 分区数,磁盘占用翻倍增长
-
ALGORITHM=INPLACE在某些版本(如5.7.29之前)对分区表不生效,实际仍走COPY流程,导致锁表时间远超预期
建议操作前先用SHOW CREATE TABLE确认当前分区结构,再用SELECT COUNT(*)抽样验证目标字段数据分布。
交换分区(EXCHANGE PARTITION)是安全迁移数据的关键手段
当需要替换某分区全部数据(比如导入新一天的日志),EXCHANGE PARTITION比TRUNCATE + INSERT快得多,且不记录完整binlog。但约束极严:
- 交换表(
table_name)必须与原分区表结构完全一致(字段名、类型、顺序、NULL属性、默认值) - 交换表不能有分区,且必须为空(
ENGINE=InnoDB下还要求无外键引用) - 交换后原分区数据直接归属交换表,原表获得交换表空结构——若忘记清空交换表,下次交换会混入脏数据
典型流程:CREATE TABLE tmp_like_tbl LIKE main_tbl; ALTER TABLE tmp_like_tbl REMOVE PARTITIONING; INSERT INTO tmp_like_tbl ...; ALTER TABLE main_tbl EXCHANGE PARTITION p20240401 WITH TABLE tmp_like_tbl;。漏掉REMOVE PARTITIONING会报错ERROR 1731 (HY000): Cannot exchange a visible partition with table。
分区数量多、数据量大时,EXCHANGE的原子性优势明显,但每一步都依赖结构强一致性,任何字段差异都会让整条命令失败。











