LOB段不会随表MOVE自动迁移,必须显式执行ALTER TABLE ... MOVE LOB(...) STORE AS (TABLESPACE ...);否则LOBSEGMENT和LOBINDEX滞留原表空间,导致空间未释放及ORA-01652错误。

LOB不能随表一起MOVE,必须显式指定MOVE LOB
执行 ALTER TABLE t MOVE TABLESPACE fast_ts 后,表数据段确实搬过去了,但所有 CLOB、BLOB 字段的 LOBSEGMENT 和 LOBINDEX 仍留在原表空间——这是最常被忽略的事实。现象是:表空间释放量远小于预期,甚至后续 ORA-01652(无法扩展临时段)错误频发,根源就在未迁移的LOB段占着旧空间不放。
真正生效的语句必须带 LOB(...) 子句和完整 STORE AS (TABLESPACE ...):
ALTER TABLE doc_table MOVE LOB (content, attachment) STORE AS (TABLESPACE fast_lob);
-
content和attachment是列名,必须真实存在且类型为LOB(CLOB/BLOB/NLOB) -
fast_lob是目标高速表空间名,不能省略;写成STORE AS (PCTVERSION 10)或只写STORE AS lob_seg_name都无效 - 多个LOB列可一次处理,用逗号分隔,避免反复锁表
为什么MOVE LOB会锁整张表且不可中断
这个操作不是DML,而是段级重组:Oracle需读取原始LOB段全部内容、在新表空间分配连续区、逐块拷贝、最后切换指针。期间表被加了排他DML锁(TX 级),INSERT/UPDATE/DELETE 全部阻塞,SELECT 仍可读——但大LOB(如GB级CLOB)可能耗时数小时,生产环境务必避开业务高峰。
- 执行前查空闲空间:
SELECT bytes/1024/1024 FROM dba_free_space WHERE tablespace_name = 'FAST_LOB',建议预留 ≥ 当前LOB段大小 × 1.2 - 确认源位置:
SELECT tablespace_name FROM dba_lobs WHERE table_name = 'DOC_TABLE' AND column_name = 'CONTENT' - 无法
ROLLBACK或CANCEL,一旦开始就得跑完
索引、分区、IOT溢出段不自动跟随,得单独处理
即使你把表和LOB都迁走了,dba_segments 里一查还会发现索引段、分区段、IOT溢出段全钉在旧表空间。它们和LOB一样,是独立段对象,Oracle不会“智能继承”目标表空间。
- 索引重建:
ALTER INDEX idx_doc_content REBUILD TABLESPACE fast_idx(别用默认表空间) - 分区表迁移单个分区:
ALTER TABLE doc_part MOVE PARTITION p2024 TABLESPACE fast_data - IOT表溢出段:
ALTER TABLE doc_iot MOVE OVERFLOW TABLESPACE fast_overflow - 别漏掉
LOBINDEX:它会随MOVE LOB自动重建并落在同表空间,无需手动干预
验证是否真搬干净了
别信“执行成功”四个字。直接查 dba_segments 最可靠:
SELECT segment_name, segment_type, tablespace_name
FROM dba_segments
WHERE owner = 'DOC_OWNER'
AND segment_name IN (
SELECT segment_name FROM dba_lobs WHERE table_name = 'DOC_TABLE'
UNION
SELECT index_name FROM dba_indexes WHERE table_name = 'DOC_TABLE'
UNION
SELECT segment_name FROM dba_tables WHERE table_name = 'DOC_TABLE'
);
结果里所有行的 tablespace_name 都应为你的高速表空间名(如 FAST_LOB、FAST_IDX)。只要有一行还指向旧表空间,就说明对应对象没处理,空间不会释放,性能瓶颈也还在原地。
最容易被跳过的其实是分区表的局部索引和IOT的溢出段——它们不像LOB那样有明显报错提示,但长期运行后会拖慢整个查询链路。


















