pctfree设太小会导致行迁移爆发,因更新后行长度增大而块内无足够预留空间,迫使oracle将整行迁至新块并保留原块指针,引发额外物理读、拖慢查询;该参数专为update预留缓冲空间,设为0几乎必然触发迁移,且对已存在迁移的老块无效,必须配合alter table move等重组操作才能解决。

PCTFREE设太小会导致行迁移爆发
当表中数据频繁更新、且更新后行长度明显变大(比如从 VARCHAR2(10) 扩到 VARCHAR2(200)),而 PCTFREE 又设得太低(如默认 10 或更低),块内没预留足够空间,Oracle 就只能把整行挪到新块——旧块留个指针,这就是行迁移。它会让一次 SELECT 变成两次物理读(先读原块取指针,再读新块取数据),严重拖慢查询。
-
PCTFREE不是“空着不用”,而是专留给UPDATE的缓冲空间;设为 0 意味着更新时几乎必然触发迁移 - 估算方法:如果某列平均更新后增长 30 字节,块可用空间约 750 字节(8K 块减去头部开销),那至少预留 30/750 ≈ 4%,建议直接设
PCTFREE 15起步 - 对已存在大量迁移的表,改
PCTFREE不起作用——老块不会自动重排;必须配合ALTER TABLE ... MOVE或DBMS_REDEFINITION
PCTUSED在ASSM下完全无效
如果你的表空间启用了自动段空间管理(SEGMENT_SPACE_MANAGEMENT = 'AUTO'),PCTUSED 就被 Oracle 忽略了。查一下:SELECT TABLESPACE_NAME, SEGMENT_SPACE_MANAGEMENT FROM DBA_TABLESPACES WHERE TABLESPACE_NAME = 'YOUR_TS'; —— 如果返回 AUTO,那就别费劲设 PCTUSED,它不会生效,也不会影响插入逻辑。
- 手动段管理(
MANUAL)才用PCTUSED控制块何时重新加入 freelist;但现在几乎没人用这种模式 - 即使你强制设了
PCTUSED,只要表空间是 ASSM,DBA_TABLES.PCT_USED字段可能仍显示旧值,但实际不起作用 - 别为了“看起来更可控”硬切回 MSSM——ASSM 的位图管理比 freelist 更高效,尤其高并发场景
调整前必须确认行迁移是否真实存在
别一上来就调参数。先用 V$SYSSTAT 和 DBA_TAB_STATISTICS 验证问题是否存在:
- 查迁移率:
SELECT TABLE_NAME, CHAIN_CNT, NUM_ROWS FROM DBA_TABLES WHERE CHAIN_CNT > 0;——CHAIN_CNT非零才说明有迁移(注意:这个值只在ANALYZE TABLE ... COMPUTE STATISTICS后更新,DBMS_STATS不统计它) - 看等待事件:
SELECT EVENT, TOTAL_WAITS FROM V$SESSION_EVENT WHERE EVENT LIKE '%row%';—— 若row cache lock或buffer busy waits异常高,可能和热块+迁移有关 - 对比执行计划中的
db block gets和consistent gets:如果前者远高于后者,说明大量单块访问,可能是迁移导致的随机IO放大
真正麻烦的是那些已经迁移的老行——参数调得再合理,不重组表就清不掉指针链。很多人卡在这一步:以为改完 PCTFREE 就万事大吉,结果监控里 chain row 计数纹丝不动。











