move操作不能直接释放extent到表空间,但能重置高水位线(hwm)、消除段内碎片,并使原extent标记为可重用;需满足表空间有≥表大小的空闲空间、索引必须重建、无需启用row movement三大前提。

MOVE操作到底能不能释放extent空间
不能直接释放 extent 到表空间,但能重置高水位线(HWM)并消除段内碎片,为后续空间回收创造条件。MOVE 本质是重建段:分配新 extent、顺序写入数据、丢弃旧 extent。原 segment 的所有 extent 会被标记为“可重用”,只要没有其他对象占用,这些空间最终会归还给表空间的空闲列表。
常见误解是“MOVE 后空间就变小了”——实际 dba_extents 中该表的 extent 数量可能不变甚至略增(因新分配的 extent 大小策略不同),但原 extent 所占物理块已释放。真正体现为空间释放的,是 dba_free_space 中对应表空间的空闲字节数上升。
执行 MOVE 前必须确认的三件事
缺一不可,否则操作失败或引发连锁问题:
-
ALTER TABLE t1 ENABLE ROW MOVEMENT不需要 —— MOVE 本身不要求启用行移动,那是SHRINK SPACE的前置条件 - 目标表空间必须有 ≥ 当前表段大小的空闲空间(不是“刚好够”,而是“至少一倍”),因为 MOVE 是先写新段再删旧段
- 表上所有索引必须在 MOVE 后
REBUILD,否则查询会报ORA-01502(索引处于不可用状态),且rowid变更导致索引指向失效
MOVE + 索引重建的最小安全操作序列
以用户 scott 下的 emp 表为例,假设它在 users 表空间中:
ALTER TABLE scott.emp MOVE TABLESPACE users; ALTER INDEX scott.pk_emp REBUILD; ALTER INDEX scott.idx_deptno REBUILD;
注意点:
- 不指定
TABLESPACE时,默认仍在原表空间 MOVE,仍需双倍空间 - 分区表要对每个分区单独 MOVE:
ALTER TABLE t1 MOVE PARTITION p1 - 含 LOB 字段的表,MOVE 后必须检查
dba_lobs,LOB 段可能未被自动迁移,需额外执行ALTER TABLE t1 MOVE LOB(col) STORE AS (TABLESPACE users) - MOVE 过程中表被加
EXCLUSIVE锁,DML 阻塞,只允许 SELECT
MOVE 后空间没明显下降?先查这三项
MOVE 完成后 SELECT SUM(bytes)/1024/1024 FROM dba_free_space WHERE tablespace_name = 'USERS' 没变化,别急着重做:
- 确认是否刚 COMMIT ——
dba_free_space视图刷新有延迟,几秒到几十秒不等,可查v$sort_segment或强制刷新 buffer cache(不推荐生产环境) - 检查是否有其他大对象(如临时段、未提交事务的回滚段)占用了刚释放的空间
- 确认表空间是本地管理(
extent_management = 'LOCAL')且段空间管理为自动(segment_space_management = 'AUTO'),否则空闲空间无法被有效跟踪和复用
最易被忽略的是:MOVE 只解决单个表的段碎片,它不触发表空间级收缩;想让数据文件物理变小,还得靠 ALTER DATABASE DATAFILE ... RESIZE,而这要求空闲空间集中在文件末尾 —— MOVE 本身不保证这一点。











