如何添加新的表分区_ALTER TABLE ADD PARTITION语法与MAXVALUE处理

2次阅读

mysql 5.7+ 和 mariadb 中 add partition 无法直接追加到含 values less than (maxvalue) 的末尾分区,必须先用 reorganize partition 将其拆分为新分区和新的 maxvalue 分区,且新分区须在前、maxvalue 在后。

alter table add partition 语法写错就直接报错

mysql 5.7+ 和 mariadb 支持 range/list 分区表的在线加分区,但 add partition 对已有 maxvalue 分区非常敏感——只要目标表末尾是 values less than (maxvalue),你就不能直接追加新分区,否则报错:Error 1503 (hy000): a primary key must include all columns in the table's partitioning function 或更常见的 error 1481 (hy000): invalid partition name,其实根本原因不是名字问题,而是语义冲突。

实操建议:

  • 先用 SHOW CREATE TABLE tbl_name 确认当前最后分区是否为 VALUES LESS THAN (MAXVALUE)
  • 如果存在,必须先用 REORGANIZE PARTITION 把它拆开,再往里塞新分区
  • ADD PARTITION 只能用于末尾没有 MAXVALUE 的情况;一旦有,它就失效
  • 不要试图用 ALTER TABLE ... ADD PARTITION (PARTITION p_new VALUES LESS THAN (MAXVALUE)) 覆盖旧的 MAXVALUE 分区——语法合法但会报错,MySQL 不允许重复定义 MAXVALUE

用 REORGANIZE 替换 MAXVALUE 分区才能继续加

这是最常卡住的一步:你想按月加一个 p202404,但表末尾是 p_max VALUES LESS THAN (MAXVALUE)。此时必须把它“切开”,腾出位置。

实操建议:

  • 假设原分区是 PARTITION p_max VALUES LESS THAN (MAXVALUE),你想加 p202404 VALUES LESS THAN (20240401),那得这样重组织:
    ALTER TABLE tbl_name REORGANIZE PARTITION p_max INTO (   PARTITION p202404 VALUES LESS THAN (20240401),   PARTITION p_max VALUES LESS THAN (MAXVALUE) );
  • 注意顺序:新分区必须在前,MAXVALUE 分区必须在后,否则 MySQL 拒绝执行
  • 该操作会锁表(非元数据锁),大表慎用;MariaDB 10.3+ 支持 ALGORITHM=INPLACE,但 MySQL 8.0 仍需 copy(除非是 NDB 引擎)
  • 数值型分区列(如 TO_DAYS(date_col))要确保新边界值类型匹配,别传字符串进去

日期字段分区时,MAXVALUE 的边界容易算错

TO_DAYS()YEAR() 或直接 DATE 列做分区键时,MAXVALUE 看似兜底,实则隐藏陷阱:它不接受任何比当前最大值小的数据,但你新加的分区如果边界值 MAXVALUE 分区。

实操建议:

  • 查清当前最大数据时间:SELECT MAX(dt) FROM tbl_name,再决定新分区上限——比如最大是 '2024-03-31',那 p202404 应设为 VALUES LESS THAN ('2024-04-01'),不是 '2024-04-30'
  • TO_DAYS('2024-04-01') 算出整数再填进 LESS THAN,避免隐式转换出错
  • 千万别写 VALUES LESS THAN (TO_DAYS('2024-04-01')) 在 DDL 里——MySQL 不支持函数调用,只接受字面量整数或 MAXVALUE
  • 测试时用 EXPLAIN PARTITIONS SELECT * FROM tbl_name WHERE dt = '2024-04-05' 确认命中预期分区

分区键含主键/唯一索引时,ADD PARTITION 会额外校验

如果表有主键或唯一索引,且分区键没包含全部索引列,ADD PARTITION 会直接拒绝,报错信息里带 PRIMARY KEY must include all columns in the table's partitioning function。这不是语法错,是设计约束。

实操建议:

  • 检查分区键是否已覆盖所有主键列(SHOW CREATE TABLE 最后一行会标出 PARTITION BY ... (col1, col2)
  • 如果主键是 (id, dt),但只按 dt 分区,就必须改成 PARTITION BY RANGE (TO_DAYS(dt)) 并确保 id 不参与分区函数——不行,得把 id 加进函数或改主键结构
  • 常见解法:把主键改成 (dt, id),让分区键 dt 成为主键前缀;否则只能放弃该表的分区,或用子分区绕过
  • 这个限制在添加任何分区(包括首次 ADD)时都生效,不是仅限于处理 MAXVALUE

真正麻烦的从来不是语法怎么写,而是你得先判断当前分区结构是否允许加——尤其当别人建的表、文档缺失、又没注释时,SHOW CREATE TABLESELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS 得翻两遍才敢动。

text=ZqhQzanResources