MySQL 8.0+ RANGE分区VALUES LESS THAN必须严格递增且类型一致,PG需手动建子表并ATTACH,Oracle添加分区前须SPLIT MAXVALUE分区,所有数据库中WHERE条件若未直连分区键将导致裁剪失效。
MySQL 8.0+ 添加 RANGE 分区时,VALUES LESS THAN 必须严格递增
分区键值范围定义错位是创建失败的头号原因。比如对 created_at 做按月 range 分区,若第二分区写成 values less than (20240301),但前一分区却是 values less than (20240215),mysql 会直接报错 error 1564 (hy000): this partition function is not allowed。
- 必须确保每个
VALUES LESS THAN的值大于前一分区的上限,且类型一致(日期用DATE或整数年月,别混用) - 最后一个分区建议用
MAXVALUE接收溢出数据,避免插入失败 - 分区表达式不能是函数调用(如
YEAR(created_at)),除非用STORED列或 MySQL 8.0+ 支持的表达式分区
PostgreSQL 12+ 使用 CREATE TABLE ... PARTITION BY LIST 需显式绑定子表
PG 不像 MySQL 那样自动管理分区子表,建完主表后,必须手动 CREATE TABLE 子表并 ATTACH PARTITION,漏掉任一环节都会导致查询不走分区裁剪。
- 子表结构必须和主表完全一致(包括列名、类型、约束,但可额外加索引)
-
ATTACH PARTITION前,子表里不能有数据;如有,先清空或用CREATE TABLE ... AS SELECT拷贝再附加 - 主表上的
PRIMARY KEY或UNIQUE约束,需包含分区键,否则附加失败:报错ERROR: unique constraint on partitioned table must include partition key
Oracle 分区表添加新分区前,必须确认 MAXVALUE 分区是否存在
很多 DBA 习惯给时间字段建 VALUES LESS THAN (MAXVALUE) 的兜底分区,但这会让 ALTER TABLE ... ADD PARTITION 失效——因为 Oracle 不允许在已有 MAXVALUE 分区后再加新分区。
- 正确做法是:先
SPLIT PARTITION原MAXVALUE分区,把新边界切出来,再保留一个缩小后的MAXVALUE分区 - 例如原分区为
P_MAX VALUES LESS THAN (MAXVALUE),想加 2024Q3 分区,应执行:ALTER TABLE t SPLIT PARTITION P_MAX INTO (PARTITION P_2024Q3 VALUES LESS THAN (20241001), PARTITION P_MAX) - 忘记这步直接
ADD,会收到ORA-14074: partition bound must collate higher than that of the last partition
所有数据库都绕不开的隐性开销:EXPLAIN 看不见的分区裁剪失效
即使语法全对、分区也建好了,查询仍可能全扫所有分区——常见于 WHERE 条件没覆盖分区键、或用了函数/表达式导致无法匹配分区逻辑。
- MySQL 中写
WHERE DATE(created_at) = '2024-05-01',会跳过分区裁剪;应改用WHERE created_at >= '2024-05-01' AND created_at - PG 中对分区键做
COALESCE(col, 'N/A')或col::text,同样让EXPLAIN显示Partition Iterator扫全部子表 - Oracle 的分区键列如果被隐式转换(如字符串字段存数字却用
WHERE part_key = 123),也可能触发全分区扫描
分区不是银弹,它只在查询条件能精准命中单个或少数几个分区时才真正生效。一旦条件模糊、跨范围或带函数,就退回全表扫描,而这个退化过程 EXPLAIN 未必明显提示。










