PCTFREE调大仅影响新插入或重写的数据块,对已填满的老块无效;必须执行ALTER TABLE ... MOVE才能让数据按新参数重写,否则行迁移率不会下降。

PCTFREE 调大能缓解行迁移,但改完不重组表等于白改
为什么 ALTER TABLE ... PCTFREE 20 不会立刻降低行迁移率
修改 PCTFREE 只影响后续新插入或移动后的数据块,对已填满的老块完全无效。老块里如果原始行+更新膨胀后超出 100 - PCTFREE(比如原设 10%,现在改到 20%,但老块早已用到 95%),照样触发行迁移——Oracle 不会自动把老块里的行“挤”出 5% 空间来适配新参数。
- 查当前行迁移率:
ANALYZE TABLE t_name LIST CHAINED ROWS INTO chained_rows;,再查chained_rows表行数 - 确认表空间是否为 ASSM:
SELECT SEGMENT_SPACE_MANAGEMENT FROM DBA_TABLESPACES WHERE TABLESPACE_NAME = 'xxx';,是AUTO则PCTUSED已失效,不用管 - 修改前先备份:
CREATE TABLE t_name_bak AS SELECT * FROM t_name;
真正起效的三步操作顺序不能错
必须让数据经过重写,才能按新 PCTFREE 分配空间。常见错误是只改参数、不触发物理重组。
- 执行
ALTER TABLE t_name MOVE PCTFREE 20;—— 这步把所有行读出、按新规则重新写入新块(注意:MOVE 期间表不可 DML,需业务窗口) - 重建所有索引:
ALTER INDEX idx_name REBUILD ONLINE;(加ONLINE可避免锁表太久) - 收集统计信息:
DBMS_STATS.GATHER_TABLE_STATS('OWNER', 'T_NAME');,否则执行计划可能不准
PCTFREE 设多少才算合理
不是越大越好。设太高浪费空间、增加 I/O 次数;设太低又挡不住迁移。关键看字段更新幅度和频率。
- 纯追加日志表(如
LOGS):几乎不更新,PCTFREE可设为 1–5 - 用户资料表(
USER_PROFILE),VARCHAR2 字段常被扩写:建议 15–25,尤其含 CLOB/TEXT 关联字段时 - 高并发计数器表(如
COUNTER):频繁 UPDATE + 热块争用,可设到 30+,配合INITRANS提升并发事务槽 - 实测技巧:用
DBA_TAB_BLOCKS或V$SEGMENT_STATISTICS查db block gets和physical reads比值突增时段,反推哪张表开始批量迁移
最易被忽略的一点:MOVE 后的块空间分配受当前表空间 INITRANS 和 MAXTRANS 影响,如果并发事务多但 INITRANS 还是默认 2,块头 ITL 槽不够,照样引发事务等待——调 PCTFREE 得同时看 INITRANS 是否匹配。











