ALTER INDEX ... REBUILD ONLINE 是唯一支持业务不中断的索引碎片释放操作,但需满足目标表空间ONLINE、空闲空间≥原索引1.2倍、数据库为企业版/开发版三条件,且重建后须手动收缩数据文件才能释放物理磁盘空间。

ALTER INDEX 加 REBUILD ONLINE 是唯一能在业务不中断前提下释放索引碎片空间的操作,但直接执行大概率失败——不是语法错,而是权限、空间、版本或对象类型挡在前面。
查哪些索引真该重建:别扫全库,盯住“大+错位”
重建不是越勤越好,只对两类索引有效:bytes > 1GB 且当前在数据表空间(比如 E3_DATA)里的索引。它们占着数据表空间的磁盘,却本该待在专用索引表空间(如 E3_INDX)。
用这条语句定位:
SELECT 'ALTER INDEX '|| owner ||'.'|| segment_name ||' REBUILD ONLINE TABLESPACE E3_INDX;' FROM dba_segments WHERE segment_type = 'INDEX' AND tablespace_name = 'E3_DATA' AND bytes > 1024*1024*1024;
-
owner必须显式拼接,否则跨用户执行会报ORA-01435: user does not exist - 结果里每条语句都带完整 schema,省略
SCOTT.会默认找当前用户,建错对象 - 如果目标表空间
E3_INDX还没建好,这条查询本身就会报错退出,不会静默跳过
执行前必须验三件事:ONLINE、空间、版本
REBUILD ONLINE 不是开关一开就跑通的命令,它依赖三个硬性条件同时满足:
- 目标表空间状态必须是
ONLINE:查SELECT status FROM dba_tablespaces WHERE tablespace_name = 'E3_INDX';——不能是READ ONLY - 空闲空间至少为原索引大小 × 1.2:重建过程双写,临时段 + 新索引共需约 2 倍空间。查
SELECT bytes/1024/1024 FROM dba_free_space WHERE tablespace_name = 'E3_INDX'; - 数据库版本必须是企业版或开发版:
STANDARD版执行会直接报ORA-00439: feature not enabled: online index operation
漏查任意一项,都会卡在 ORA-01653(空间不足)、ORA-01702(LOB/VARCHAR2(MAX) 列不支持)或锁表超时上。
重建后空间没下来?关键一步常被跳过
索引重建完,dba_segments 里它的 bytes 确实变小了,但磁盘文件(datafile)实际占用没变——Oracle 不自动收缩物理文件。
- 先确认原索引所在表空间(比如
E3_DATA)是否真有可回收空间:SELECT max(block_id) FROM dba_extents WHERE file_id = <id> AND tablespace_name = 'E3_DATA'; - 再用
ALTER DATABASE DATAFILE '<path>' RESIZE <new_size>M;手动缩小文件。注意:新尺寸必须 ≥ 上一步算出的最高块位置 × 块大小 - 如果没做这步,监控看到的磁盘使用率根本不会降,白忙一场
为什么不用 DROP + CREATE?
有人图省事想 DROP INDEX 再 CREATE INDEX,这等于主动制造停机窗口:
-
DROP后索引立刻失效,所有走该索引的查询变慢或走全表扫描 -
CREATE过程全程锁表,DML 阻塞,对在线系统就是服务中断 - 重建失败时无法回滚到旧索引,风险远高于
REBUILD ONLINE
真正麻烦的从来不是命令怎么写,而是重建前后没人去查 dba_free_space 和 dba_data_files——空间没释放,是因为你没动物理文件,不是索引没 rebuild 成功。


















