ALTER TABLE … COMPRESS PARTITION 在只读表空间必然失败,因压缩需更新段元数据、数据字典及生成 undo,而只读表空间禁止任何写入,触发 ORA-00372 或 ORA-01647;正确做法是通过 EXCHANGE PARTITION 临时移出分区至读写表空间压缩后再换回。
不能直接对只读表空间里的分区执行 alter table …… compress —— oracle 会报 ora-00372 或 ora-01647,因为压缩操作需要写入数据字典和段头,而只读表空间禁止任何写入。
为什么 ALTER TABLE …… COMPRESS PARTITION 在只读表空间上必然失败
压缩分区本质是重建该分区的物理存储(HCC 或 BASIC 压缩),涉及:segment 元数据更新、data dictionary 修改、以及可能的 undo 记录生成。只读表空间连 INSERT 都不允许,更别说这些后台写操作。
常见错误现象:
-
ORA-00372: file 5 cannot be modified at this time(文件属于只读表空间) ORA-01647: tablespace 'HIST_RO' is read-only, cannot allocate space in it-
ORA-14402: updating partition key column would cause a partition change(误以为是分区键问题,其实是底层权限 / 状态冲突)
正确路径:先切出分区 → 压缩 → 换回(不碰只读表空间)
核心思路是绕过“在只读空间里压缩”,改为把分区临时移到可写的表空间中操作。适用于已归档但尚需保留在线查询的历史分区。
实操步骤:
- 用
ALTER TABLE …… EXCHANGE PARTITION把目标分区和一个空的、位于读写表空间的STAGING表交换(注意:STAGING表结构、约束、统计信息需严格一致) - 对
STAGING表执行ALTER TABLE …… COMPRESS FOR OLTP(或QUERY LOW/HIGH) - 再用
EXCHANGE PARTITION换回去 —— 此时被换回的已是压缩后的数据段 - 最后确认
USER_TAB_PARTITIONS.COMPRESSION和SEGMENT_NAME对应的BYTES是否下降
注意:EXCHANGE 不移动数据,只交换数据字典指针,所以很快;但要求两个段的 TABLESPACE 必须同为读写,或都为只读 —— 所以 STAGING 表必须建在读写表空间。
COMPRESS 参数选错会导致白忙活
历史分区通常只读、极少更新,但不同压缩类型对后续查询性能影响差异很大,且不可逆(除非解压重做)。
-
COMPRESS FOR QUERY LOW:适合即席分析类查询,CPU 开销低,压缩率一般(~2x),SELECT性能损失小 -
COMPRESS FOR QUERY HIGH:压缩率高(~4–5x),但解压 CPU 成本明显上升,OLAP 场景可接受,报表类查询慎用 -
COMPRESS FOR ARCHIVE LOW/HIGH:仅限 Oracle 12c+,专为冷数据设计,但要求表空间启用INMEMORY或使用HEAT MAP,且ARCHIVE类型在只读场景下实际很少启用(兼容性差、工具链支持弱)
别用 COMPRESS FOR OLTP —— 它依赖 ITL 和行迁移优化,对只读分区无意义,反而增加块头开销。
容易被忽略的检查点:统计信息与全局索引
交换分区后,Oracle 不自动更新统计信息,也不刷新全局索引状态 —— 这会导致执行计划劣化或查询报错。
- 交换前后都跑一次
DBMS_STATS.GATHER_TABLE_STATS,特别指定GRANULARITY => 'PARTITION' - 如果表有全局索引,
EXCHANGE会使其失效(STATUS = UNUSABLE),必须手动ALTER INDEX …… REBUILD PARTITION或整个重建 - 检查
USER_IND_PARTITIONS中对应索引分区的COMPRESSION列 —— 它不会随表分区自动继承,需单独设置
最常漏掉的是索引状态,一上线就发现查询变慢或报 ORA-01502,回头查才发现索引没 rebuild。






























