PCTFREE值需结合数据增长模式判断:avg_row_len与块大小不匹配且chain_cnt/num_rows>0.05时说明不足;20~30为常用合理范围,过高或过低均影响性能;调整后须MOVE或重建表并验证chain_cnt是否止涨。

查当前PCTFREE值是否合理
直接查 user_tables.pct_free 是第一步,但不能只看数字。比如查到 pct_free = 10,这在多数场景下就是隐患——尤其表里有 VARCHAR2(4000) 这类字段,或 UPDATE 频繁。真正要判断的是:该值是否匹配数据增长模式。如果 avg_row_len 是 200,块大小是 8192,但 chain_cnt / num_rows > 0.05,那基本能断定 pct_free 不够用。
设多大才算够:20~30不是拍脑袋
这个范围来自实际观测:当行平均扩容幅度在 30%~50%(比如从 200 字节涨到 300 字节)且 UPDATE 密集时,pct_free = 20 能让大多数块在更新后仍有空间容纳整行;设到 30 是为应对极端扩容(如日志字段追加大量文本)。但注意:
-
pct_free = 0或1确实省空间,但等于关闭所有更新缓冲,chain_cnt会飙升 - 设太高(如
50)会导致单块存的行数锐减,逻辑读上升,反而拖慢全表扫描 - 对只读表或极少更新的维度表,
pct_free = 5可接受,但必须确认后续无 DML 计划
改完PCTFREE不生效?因为老块没重排
ALTER TABLE t1 pctfree 25 只影响新插入的数据块,对已填满的老块完全无效。这就是为什么调完参数立刻查 chain_cnt 没变化。必须配合重组才能落地:
- 用
ALTER TABLE t1 MOVE最快,但索引全失效,得重建 -
CREATE TABLE t1_new AS SELECT * FROM t1更稳妥,可加STORAGE (PCTFREE 25)显式控制 - 别用
SHRINK SPACE——它不移动已迁移的行,chain_cnt不降,甚至可能因重排触发新迁移
ASSM下PCTUSED已失效,别再配它
如果你的表空间是 SEGMENT_SPACE_MANAGEMENT = AUTO(现在默认都是),pct_used 参数已被 Oracle 忽略。查 user_tables.pct_used 可能返回 NULL 或陈旧值。此时空间回收由位图自动管理,唯一可控入口就是 pct_free。强行在 ASSM 表空间里设 pct_used 不报错,但毫无作用。
真正容易被忽略的是:PCTFREE 调整后必须验证迁移是否真被遏制,而不是只看参数改没改成功。最简验证法是跑一轮典型 UPDATE 后,立刻 DBMS_STATS.GATHER_TABLE_STATS,再查 chain_cnt 是否止涨。否则过两周又回到原点。


















