delete后全表扫描变慢是因为仅标记数据为已删除而不降低高水位线(hwm),导致select仍需扫描hwm下所有数据块,包括大量空块;可通过dba_segments.bytes与dba_tables.blocks偏大但num_rows极小、或count(distinct rowid_block_number)远小于blocks来确认;推荐先shrink space compact再shrink space,或使用move+rebuild、truncate+insert等方案。

为什么DELETE之后全表扫描还是慢
因为DELETE只删数据,不降高水位线(HWM)。Oracle执行SELECT *或COUNT(*)时,仍会扫描HWM以下所有数据块——哪怕其中99%是空的。你看到的“50G大表只有10行”,就是HWM卡在高位的典型症状。
怎么快速确认是不是HWM问题
别猜,查两个关键指标:
-
DBA_SEGMENTS.bytes和DBA_TABLES.blocks明显偏大,但DBA_TABLES.num_rows很小(比如几万行却占几个GB) - 执行
SELECT COUNT(DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) FROM table_name,结果远小于blocks值(说明大量块是空的)
注意:查之前先运行 DBMS_STATS.GATHER_TABLE_STATS,否则统计不准;ANALYZE TABLE ... COMPUTE STATISTICS 也得做一次,因为 empty_blocks 只有 ANALYZE 才能填上。
ALTER TABLE SHRINK SPACE 是最常用解法,但容易失败
它在线收缩、调低HWM、释放空间回表空间,但有硬性前提:
- 表空间必须是本地管理(
LOCAL),且启用了自动段空间管理(ASSM)——查DBA_TABLESPACES.segment_space_management - 必须先开行移动:
ALTER TABLE your_table ENABLE ROW MOVEMENT - 不能有基于函数的索引、域索引、物化视图日志等特殊对象(否则报错
ORA-10636)
推荐分两步执行,更稳:ALTER TABLE t SHRINK SPACE COMPACT(先整理块内碎片),再 ALTER TABLE t SHRINK SPACE(真正降HWM)。一步到位虽快,但锁表时间更长,业务抖动风险高。
MOVE和在线重定义的取舍关键点
当 SHRINK SPACE 不可用时,选哪个?看三点:
-
MOVE快、简单,但必须离线——整个过程表不可DML,且索引全失效,得手动ALTER INDEX ... REBUILD -
DBMS_REDEFINITION真正在线,适合7×24系统,但操作步骤多(校验、创建中间表、同步、切换),且对主键/唯一约束、外键依赖有要求 - 如果只是临时清理,又不怕停机,
TRUNCATE+INSERT /*+ APPEND */最干脆——但前提是能接受短暂停写
HWM本质是段级标记,不是表级开关。哪怕你只删了10%数据,只要触发过区扩展,HWM就可能已抬升;而一次SHRINK失败后,残留的COMPACT状态会让后续操作更难推进——这点常被忽略。











