如何压缩分区表中的历史分区_ALTER TABLE COMPRESS与只读表空间结合

2次阅读

ALTER TABLE … COMPRESS PARTITION 在只读表空间必然失败,因压缩需更新段元数据、数据字典及生成 undo,而只读表空间禁止任何写入,触发 ORA-00372 或 ORA-01647;正确做法是通过 EXCHANGE PARTITION 临时移出分区至读写表空间压缩后再换回。

不能直接对只读表空间里的分区执行 alter table …… compress —— oracle 会报 ora-00372ora-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.COMPRESSIONSEGMENT_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。

text=ZqhQzanResources