必须先删除long列并新建clob列再迁移数据,因ora-22858禁止直接修改;to_lob()仅支持insert select单向转换,dbms_redefinition完全不支持long列。
ora-22858: 不能直接修改 long 列所在的表结构
oracle 中 long 类型是被废弃的旧数据类型,不支持分区、索引、约束、物化视图等现代特性。想把含 long 的表转为分区表,**必须先替换掉 long 列**——不是“改类型”,而是“删旧列 + 加新列 + 迁移数据”。直接执行 alter table ... modify column ... clob 会报 ora-22858,这是 oracle 硬性限制。
常见错误现象:ALTER TABLE t1 MODIFY (notes LONG TO CLOB) 报错;或用 DBMS_REDEFINITION 时卡在 CHECK_DEPENDENCIES 阶段失败,提示 LONG 不支持在线重定义。
- 唯一可行路径:停写 + 建新表(
CLOB替代LONG)+INSERT /*+ APPEND */ SELECT迁移 + 重命名切换 - 别信“加虚拟列”“用函数转换”这类绕路方案——
LONG无法参与任何表达式计算,TO_LOB()是唯一合法转换函数,且只能用于SELECT子句或INSERT的值来源 - 如果表上有触发器、外键或物化日志,迁移前要先禁用/记录,否则
INSERT可能失败或产生不一致
TO_LOB() 函数只在 INSERT 场景下有效
TO_LOB() 不是类型转换函数,它是个“单向搬运工”:只允许把 LONG 列内容一次性注入到目标 CLOB 列中,且仅限于 INSERT ... SELECT 语句。在 UPDATE 或 PL/SQL 变量赋值里调用会报 ORA-00932。
使用场景很窄:建好新表后,用它把旧 LONG 数据搬进新 CLOB 列。不能用来做运行时转换,也不能嵌套在其他函数里。
- 正确写法:
INSERT INTO t1_new (id, notes) SELECT id, TO_LOB(notes) FROM t1_old - 错误写法:
UPDATE t1_new SET notes = TO_LOB((SELECT notes FROM t1_old WHERE id = t1_new.id))—— 子查询返回LONG,不被允许 - 注意空值:若原
LONG列为NULL,TO_LOB(NULL)结果仍是NULL,无需额外处理
DBMS_REDEFINITION 对 LONG 列完全无效
很多人想用 DBMS_REDEFINITION 实现在线重定义来规避锁表,但 Oracle 明确不支持含 LONG 列的表进行重定义。调用 START_REDEFINITION 之前,CHECK_DEPENDENCIES 就会直接报错:ORA-23539: table "T1" contains a LONG column and cannot be redefined。
这不是权限或版本问题,是设计层面的硬拦截。哪怕你手动建好结构一致的新表(含 CLOB),只要源表还有 LONG,DBMS_REDEFINITION 就走不通。
- 替代方案只有两个:停业务窗口期执行 DDL+DML,或用逻辑复制工具(如 GoldenGate)同步变更,但后者仍需先完成初始全量迁移(还是得用
TO_LOB()) - 别尝试把
LONG改成LONG RAW再转——同样不支持,且更难处理 - 如果表特别大(>100GB),考虑分批
INSERT /*+ APPEND */+ 手动提交,避免 UNDO 和 REDO 压力爆炸
分区表创建后,CLOB 列的存储和索引要注意什么
把 LONG 换成 CLOB 只是第一步。后续建分区表时,CLOB 列默认启用 ENABLE STORAGE IN ROW,小数据存行内,大数据存 LOBSEGMENT。这会影响分区裁剪效果和统计信息准确性。
性能影响明显:如果大量 CLOB 值 > 4000 字节,查询带 WHERE 条件时可能无法利用分区剪枝,因为优化器难以准确估算 LOB 列分布。
- 建议显式指定
DISABLE STORAGE IN ROW,强制所有CLOB存 LOBSEGMENT,让分区键与 LOB 存储分离,提升可预测性 -
CLOB列不能直接建普通 B-tree 索引,如需搜索内容,用CTXSYS.CONTEXT全文索引,但注意它不支持分区表的本地域索引(必须 GLOBAL) - 迁移后务必收集新表统计信息:
DBMS_STATS.GATHER_TABLE_STATS,否则分区表的执行计划可能严重失真
真正麻烦的不是语法,是 LONG 列像一块胶水,把表和各种依赖粘得太死——触发器、物化视图日志、审计策略、甚至某些老旧应用的绑定变量逻辑都可能隐式依赖它的行为。动手前,先 SELECT * FROM DBA_TAB_COLUMNS WHERE DATA_TYPE = 'LONG' 确认范围,再逐个检查依赖对象。










