CREATE TABLE时必须显式指定PARTITION BY RANGE,不可省略或误写为LIST;分区键须为单列DATE/TIMESTAMP类型;VALUES LESS THAN需用静态日期字面量如DATE '2024-01-01',且边界严格递增,末分区建议用MAXVALUE。
CREATE TABLE 时必须显式指定 PARTITION BY RANGE
oracle 不会自动识别日期列就启用范围分区,partition by range 是强制语法节点。漏写或错写成 partition by list 会导致建表失败,错误信息是 ora-00922: missing or invalid option。
常见错误:把时间列直接放在 VALUES LESS THAN 里,比如写成 VALUES LESS THAN (created_at) —— 这是非法的,必须用具体字面值或表达式(如 DATE '2024-01-01')。
- 时间列类型建议统一用
DATE或TIMESTAMP,避免混用导致分区边界计算异常 - 分区键只能是单列;如果想按年月组合分区,得先建虚拟列或用
EXTRACT(YEAR FROM ...)表达式(但注意表达式分区要求 Oracle 11gR2+ 且需函数索引支持) - 首次建表至少要定义一个
VALUES LESS THAN分区,否则报ORA-14021: MAXVALUE must be specified for all columns
按月分区时,VALUES LESS THAN 必须用标准日期字面量
很多人用 TO_DATE('202401', 'YYYYMM') 或 ADD_MONTHS(...) 动态生成边界,这在 CREATE TABLE 语句里不被允许——DDL 要求边界值可静态解析。
正确做法是硬编码 DATE '2024-01-01'、DATE '2024-02-01' 等。虽然看起来不灵活,但这是 Oracle 的硬性限制。
- 别用字符串拼接日期,例如
'2024-01-01'没加DATE前缀会被当字符处理,分区可能不生效 - 边界值必须严格递增,且最后一个分区建议用
MAXVALUE接收未来数据,否则插入超界时间会报ORA-14400: inserted partition key does not map to any partition - 月份边界设为每月 1 日零点(
DATE '2024-02-01'),不是月末,否则会漏掉当月最后一天的数据
分区裁剪失效的三个典型原因
建完表不代表查询一定走分区裁剪。即使 WHERE 条件写了 create_time >= DATE '2024-01-01',也可能全表扫描。
- WHERE 中对分区键用了函数,如
TRUNC(create_time) = DATE '2024-01-01'—— 函数会阻断裁剪,改用范围条件create_time >= DATE '2024-01-01' AND create_time - 绑定变量类型与分区键不一致,比如
create_time = :v1,而:v1被 Oracle 推断为VARCHAR2,会导致隐式转换,裁剪失效 - 统计信息过期或缺失,执行
DBMS_STATS.GATHER_TABLE_STATS是必须步骤,否则优化器无法估算各分区数据量
维护新分区要用 ALTER TABLE ADD PARTITION,不是 INSERT
每月初要为下个月准备分区,靠 DML 插入数据进新分区是错的——分区不存在时插入会直接报错 ORA-14400。
必须提前用 ALTER TABLE ... ADD PARTITION 扩展结构。自动化脚本里常犯的错是:用 SYSDATE 计算下月边界却没加时区处理,导致跨时区数据库生成错误边界。
- 推荐用
ADD PARTITION p_202402 VALUES LESS THAN (DATE '2024-03-01')这种明确写法,别依赖NUMTODSINTERVAL类动态表达式 - 添加前检查是否存在同名分区,避免
ORA-14074: partition bound must collate higher than that of the last partition - 大表加分区会持有 DDL 锁,线上操作尽量避开高峰,且确认归档模式开启(防止
ORA-14403异常中断)
时间分区真正难的不是建表那一刻,而是后续几个月是否能稳定维持边界连续、统计信息准确、应用查询不绕过裁剪——这些细节一漏,分区就退化成“带壳的普通表”。










