ALTER TABLE ... MOVE 或 MOVE PARTITION 是强制重写数据块以激活 Advanced Row Compression 的唯一方式,仅设 COMPRESS FOR OLTP 表属性不压缩历史数据,压缩效果需通过段空间对比和 AVG_ROW_LEN 下降验证。
段合并压缩本身不节省空间,真正起效的是 compress for oltp(即 advanced row compression)在数据块重写时触发的行级字典压缩,而 alter table ... move 或 move partition 是强制重写的手段。
为什么只改表定义不压缩已有数据
建表时加 COMPRESS 或 COMPRESS FOR OLTP 只是设置属性,不触发行压缩。Oracle 不会在后台自动扫描并重写旧数据块——它只对新写入或重写的块生效。
-
DBA_TABLES.COMPRESSION显示ENABLED≠ 数据已压缩,只是“允许压缩” - 普通
INSERT INTO t VALUES (...)写入的块仍是未压缩格式,哪怕表定义带COMPRESS FOR OLTP - 只有
INSERT /*+ APPEND */、ALTER TABLE ... MOVE、ALTER TABLE ... MOVE PARTITION这类物理重写操作,才会按当前压缩策略重新组织数据块
MOVE 操作如何让 Advanced Row Compression 生效
MOVE 强制将每个数据块读出、解压(如果原本已压缩)、按新压缩规则重新编码、再写回——这是唯一能“激活”历史数据压缩的方式。
- 对非分区表:
ALTER TABLE t1 MOVE ROW STORE COMPRESS ADVANCED,会锁全表、产生大量 redo - 对分区表:
ALTER TABLE t1 MOVE PARTITION p2 ROW STORE COMPRESS ADVANCED ONLINE,需先ENABLE ROW MOVEMENT,且要求有主键/唯一约束(否则局部索引重建可能失败) - 移动后必须手动
REBUILD局部索引;全局索引自动维护但建议检查DBA_INDEXES.STATUS - 压缩率取决于数据重复度:高基数低重复字段(如 GUID、时间戳)压缩效果弱;低基数字段(如状态码、地区码)收益明显
验证压缩是否真起作用,别信表定义
查 DBA_TAB_PARTITIONS.COMPRESS_FOR 或 DBA_TABLES.COMPRESS_FOR 只告诉你“用了什么策略”,不是“压了多少”。真实效果得看段空间和块结构。
- 对比移动前后:
SELECT BYTES/1024/1024 MB FROM DBA_SEGMENTS WHERE SEGMENT_NAME = 'T1' AND PARTITION_NAME = 'P2' - 执行
ANALYZE TABLE t1 COMPUTE STATISTICS后查DBA_TABLES.AVG_ROW_LEN,下降才说明压缩生效 - 用
DBMS_ROWID.ROWID_BLOCK_NUMBER抽样几行,再结合V$BH查对应块的CLASS和STATUS,确认是否落在压缩段中 - 注意:
SELECT COUNT(*)结果不变,压缩不影响逻辑结果
容易被忽略的关键限制
Advanced Row Compression 不是万能开关,几个硬性边界常导致“明明开了却没压”:
- 不支持索引组织表(IOT)、外部表、临时表、物化视图日志表
- 分区表中,每个分区可独立设压缩策略,
ALTER TABLE ... COMPRESS FOR OLTP不影响已有分区 - 即使启用了
COMPRESS FOR OLTP,UPDATE仍可能产生少量未压缩行(SMON 后台异步清理),大并发更新后建议观察V$SESSION_LONGOPS中的 “clean up” 任务 - 表空间级压缩(
DEFAULT ROW STORE COMPRESS ADVANCED)仅影响后续新建表,不改变已有表行为
压缩本质是拿 CPU 换 I/O 和空间,但 Oracle 的 Advanced Row Compression 设计上尽量减少读开销——压缩块可直接参与 buffer cache 和 SQL 执行,不需要运行时解压。真正要盯住的,是 MOVE 时机、分区粒度、以及验证时是否跳过了段统计直接信了表定义。


















