问题背景
快速删除列是一个新特性,该特性在OB4.2.1.4引进的,对于Oracle租户来说,删列操作从真正删除变更为标记删除,极大提升了删列性能。删列后,对应列以隐藏列方式存储。如果业务存在较频繁的删列行为使隐藏列累积到128个,会阻塞该表的加列和删列操作,需要通过命令进行隐藏列清理。清理过程中会锁表和重整数据,阻塞其他事务。在生产环境中可能很少遇到隐藏列累积到128个,但在测试环境中遇到的概率就比较大,如果遇到如下错误,那就说明刚好遇到这个小坑。
报错信息
ORA-00600: internal error code, arguments: -4179, The number of obsolete columns reaches the limit. Use “alter table table_name force” to defragment first,otherwise dropping column is not allowed
对于这个新特性引进还需要注意以下,如果在业务层需要判断某个表字段列或者获取所有的列,尽可能使用user_tab_columns,不要使用all_tab_cols等视图,如果一定要使用,还需要排除一些特定字段才行。另外提下,如果对一张表删列,在使用ob导数工具(V4.3.0)之前导出结构和数据,此时就可能会报错,因为导数版本内部使用的逻辑就是使用了all_tab_cols,如果遇到这个错误,也是需要将导数版本升级至V4.3.0及以上。
复现步骤
drop table t11;
create table t11 (id number,name varchar2(20));
select owner,table_name,column_name from all_tab_cols where table_name=‘T11’; – 返回2行
alter table t11 drop column name;
select owner,table_name,column_name from all_tab_cols where table_name=‘T11’; – 还是返回2行,多了SYS_XXX_XXX$
解决方法
若在日常使用中碰到,可执行如下匿名块来清理。Oracle租户使用obclient或odc登陆到对应的用户中。
DECLARE
v_sql varchar2(4000);
BEGIN
FOR i IN (select owner,table_name from all_tab_cols where column_name like ‘SYS_%$’ and owner not in (’__recyclebin’)) LOOP
v_sql := ‘ALTER TABLE ‘||i.owner||’.’||i.table_name||’ FORCE’;
EXECUTE IMMEDIATE v_sql;
– DBMS_OUTPUT.PUT_LINE(v_sql);
END LOOP;
END;
/





