LOB字段不能直接用ALTER TABLE MOVE迁移,必须用MOVE LOB子句显式指定并带TABLESPACE;否则LOB段仍在原表空间,且操作不可中断、需预估时间并手动清理旧段。
LOB字段不能直接用ALTER TABLE MOVE迁移
直接对含lob字段的表执行alter table ... move会失败,因为lob数据不随表段一起移动——它有自己的段(lobsegment)和索引(lobindex),且默认与表在同一个表空间。报错典型如:ora-10631: the shrink clause cannot be used for this object或更常见的ora-22858: invalid alteration of datatype(尤其当你顺手加了modify之类操作时)。
真正要迁移LOB数据,必须显式指定LOB列并用MOVE LOB子句:
ALTER TABLE t1 MOVE LOB (clob_col) STORE AS (TABLESPACE ts_new);- 若同时要移动表本身,得拆成两步:先
MOVE表(不含LOB),再单独MOVE LOB - 多个LOB列可一次写全:
MOVE LOB (c1, c2, b1) STORE AS (...)
STORE AS子句里必须指定TABLESPACE,不能省略
很多人复制示例时漏掉TABLESPACE,结果触发默认行为——LOB段仍建在原表空间,看似执行成功,实则白忙活。Oracle不会自动继承你前面MOVE TABLE的目标表空间。
正确写法必须带TABLESPACE:
ALTER TABLE doc_table MOVE LOB (content) STORE AS (TABLESPACE users_lob);
常见错误写法(无效):
-
STORE AS (PCTVERSION 10)—— 没指定表空间,LOB仍在原地 -
STORE AS lob_seg_name—— 这是重命名段名,不是换表空间 - 完全省略
STORE AS—— 语法报错
MOVE LOB会锁表且不可中断,大LOB要预估时间
这个操作是DML级锁,期间表不可DML(SELECT仍可),而且一旦开始就不能ROLLBACK或CANCEL。如果LOB列数据量大(比如TB级CLOB),迁移可能持续数小时。
执行前建议确认:
- 目标表空间有足够空闲空间(至少是当前LOB段大小的1.2倍)
- 检查
DBA_LOBS视图确认当前LOB段位置:SELECT tablespace_name FROM dba_lobs WHERE table_name='DOC_TABLE' AND column_name='CONTENT'; - 生产环境务必安排窗口期,避免高峰期执行
MOVE后LOB索引也跟着换了表空间,但名字不变
不需要手动处理LOB索引——MOVE LOB会自动重建LOBINDEX段,并放在和新LOB段相同的表空间里。索引名保持默认(如SYS_IL00001234567890$),不用重命名或单独MOVE。
验证方式:
SELECT segment_name, segment_type, tablespace_name FROM dba_segments WHERE segment_name IN ( SELECT index_name FROM dba_indexes WHERE table_name = 'DOC_TABLE' );
注意:如果原LOB索引已手工重命名过,MOVE后仍沿用原名;但只要没显式指定INDEX子句,Oracle就按默认规则重建。
最易被忽略的一点:MOVE LOB之后,旧LOB段不会自动清理,需要等后续归档日志切换+空间回收(或手动ALTER TABLE ... DEALLOCATE UNUSED),否则表空间占用看起来“没变少”。










