应先用dbms_advisor.create_task创建segment advisor任务,再通过create_object指定目标表对象,调用set_task_parameter设置参数后执行execute_task,最后查询dba_advisor_findings获取可收缩建议;不能跳过分析直接shrink,因advisor需评估hwm、碎片分布及可回收空间才生成可靠recommendation。
直接回答:用 dbms_advisor.tune_task 手动运行 segment advisor 任务,再查 dba_advisor_findings 获取可收缩的表建议。
怎么手动创建并执行 Segment Advisor 任务
Automatic Segment Advisor 默认每晚运行,但若刚清理过数据、急需回收空间,或想验证某张表是否真有碎片,就得手动触发。不能跳过任务创建直接“一键收缩”——Oracle 要先分析段使用率、HWM 和空闲块分布,才敢建议 SHRINK。
- 先建任务:
BEGIN DBMS_ADVISOR.CREATE_TASK('SEGMENT_ADVISOR', :task_id, 'MY_SEG_TASK'); END; - 设目标对象(比如只看
SCOTT.EMP):BEGIN DBMS_ADVISOR.SET_TASK_PARAMETER('MY_SEG_TASK', 'OBJECT_TYPE', 'TABLE'); DBMS_ADVISOR.SET_TASK_PARAMETER('MY_SEG_TASK', 'OBJECT_NAME', 'EMP'); DBMS_ADVISOR.SET_TASK_PARAMETER('MY_SEG_TASK', 'OBJECT_OWNER', 'SCOTT'); END; - 执行:
EXEC DBMS_ADVISOR.EXECUTE_TASK('MY_SEG_TASK'); - 查结果:
SELECT message, more_info FROM dba_advisor_findings WHERE task_name = 'MY_SEG_TASK';
注意:任务名必须唯一;OBJECT_OWNER 区分大小写;若不指定对象,默认扫描整个库(耗时长,慎用)。
为什么不能跳过 Advisor 直接 SHRINK
因为 SHRINK SPACE 不是“智能压缩”,它只按 HWM 下移数据块,但不会判断“值不值得收缩”。比如一张表删了 90% 行,但剩余行分散在大量块中(高碎片),SHRINK 后仍占很多空间——Advisor 就会告诉你“可回收 XX MB”,而如果只是刚插入又回滚,块没真正释放,Advisor 可能压根不推荐收缩。
- ORA-10631 错误常在此出现:Advisor 没报错,你硬 SHRINK 含函数索引的表,就崩
- 没开
ENABLE ROW MOVEMENT的表,SHRINK 直接报 ORA-10636 - Segment Advisor 的
recommendation字段含 “reclaimable” 才代表真有空间可收,别信bytes字段单看大小
查出可收缩表后,怎么安全生成执行语句
别手敲 ALTER TABLE,容易漏 CASCADE 或忘关 ROW MOVEMENT。用系统视图拼 SQL 最稳:
SELECT
'ALTER TABLE '||owner||'.'||segment_name||' ENABLE ROW MOVEMENT;' cmd1,
'ALTER TABLE '||owner||'.'||segment_name||' SHRINK SPACE CASCADE;' cmd2,
'ALTER TABLE '||owner||'.'||segment_name||' DISABLE ROW MOVEMENT;' cmd3,
ROUND((s.bytes - f.bytes)/1024/1024, 1) "RECLAIMABLE_MB"
FROM dba_advisor_findings f
JOIN dba_segments s ON f.owner = s.owner AND f.object_name = s.segment_name
WHERE f.task_name = 'MY_SEG_TASK'
AND f.recommendation LIKE '%reclaimable%'
AND s.segment_type = 'TABLE'
AND s.owner NOT IN ('SYS','SYSTEM','XDB')
ORDER BY "RECLAIMABLE_MB" DESC;
- 执行前务必加
COMPACT测试:SHRINK SPACE COMPACT只整理块内空隙,不下移 HWM,不锁全表,适合业务期试跑 - 含位图索引或函数索引的表,得先
ALTER INDEX idx_name UNUSABLE;再 SHRINK,完事再REBUILD -
CASCADE会连带收缩索引段,但不会重建索引结构——索引碎片还得单独ALTER INDEX ... REBUILD ONLINE
执行 SHRINK 时最容易被忽略的锁行为
很多人以为 SHRINK 是纯在线操作,其实它在关键步骤会抢一个瞬时 X 锁,但这个“瞬时”不是毫秒级——如果表正被大批量 INSERT/UPDATE 持有 TX 锁,SHRINK 会等,可能卡住几分钟,甚至触发死锁监控告警。
- 查当前阻塞:
SELECT blocking_session, sid, event FROM v$session WHERE blocking_session IS NOT NULL; - 别在应用批量导入时段跑;优先选凌晨或维护窗口
-
SHRINK SPACE COMPACT阶段允许 DML,但SHRINK SPACE(下移 HWM)阶段禁止任何 DDL,且会短暂阻塞新事务获取 ITL 插槽 - 收缩后务必
ANALYZE TABLE ... COMPUTE STATISTICS或用DBMS_STATS刷新统计信息,否则执行计划可能劣化
真正麻烦的从来不是命令怎么写,而是你不知道哪张表 SHRINK 后会让某个慢查询突然变快,或者哪张表 SHRINK 时悄悄把主键索引弄失效了——得盯 dba_indexes.status 和 v$segment_statistics 里的物理读变化。











