暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle使用alter table set unused删除字段的小技巧

IT那活儿 2021-08-04
2027
 背 景 
Oracle的删除字段操作,常规方法是使用alter table table_name drop column column_name;或者alter table_name drop (column_name1, column_name2);,但是对于大表来说,删除字段的过程会消耗大量时间和资源,甚至会导致锁表。

解决方法
使用ALTER TABLE SET UNUSED COLUMN在逻辑上删除字段,等系统空闲时再ALTER TABLE DROP UNUSED COLUMNS。
  • 示例

1. 创建示例表

SQL> create table test.objects as select * from dba_objects;Table created.SQL> select count(*) from test.objects;  COUNT(*)----------     86984SQL> desc test.objects  Name                                      Null? Type ----------------------------------------- -------- ---------------------------- OWNER                                              VARCHAR2(30OBJECT_NAME                                        VARCHAR2(128SUBOBJECT_NAME                                     VARCHAR2(30OBJECT_ID                                          NUMBER DATA_OBJECT_ID                                     NUMBER OBJECT_TYPE                                        VARCHAR2(19CREATED                                            DATE LAST_DDL_TIME                                      DATE TIMESTAMP                                          VARCHAR2(19STATUS                                             VARCHAR2(7TEMPORARY                                          VARCHAR2(1GENERATED                                          VARCHAR2(1SECONDARY                                          VARCHAR2(1NAMESPACE                                          NUMBER EDITION_NAME                                       VARCHAR2(30)

2. 删除字段

在逻辑上删除OBJECT_ID字段:

SQL> alter table test.objects set unused column OBJECT_ID;Table altered.

一旦执行该语句,OBJECT_ID字段就不再可见。

SQL> desc test.objects  Name Null? Type ----------------------------------------- -------- ---------------------------- OWNER VARCHAR2(30) OBJECT_NAME VARCHAR2(128) SUBOBJECT_NAME VARCHAR2(30) DATA_OBJECT_ID NUMBER OBJECT_TYPE VARCHAR2(19) CREATED DATE LAST_DDL_TIME DATE TIMESTAMP VARCHAR2(19) STATUS VARCHAR2(7) TEMPORARY VARCHAR2(1) GENERATED VARCHAR2(1) SECONDARY VARCHAR2(1) NAMESPACE NUMBER EDITION_NAME VARCHAR2(30)SQL> select OBJECT_ID from test.objects ;select OBJECT_ID from test.objects       *ERROR at line 1:ORA-00904: "OBJECT_ID": invalid identifier

可以从dba_unused_col_tabs视图查看表中unused的字段数:

SQL> select * from dba_unused_col_tabs;OWNER TABLE_NAME COUNT------------------------------ ------------------------------ ----------TEST OBJECTS 1

使用以下语句删除表中所有unused的字段:

SQL> alter table test.objects drop unused columns;Table altered.

如果要减少产生的undo日志数量,可以使用在处理了指定的行数之后强制执行检查点的选项:

SQL> alter table test.objects drop unused columns checkpoint 250;Table altered.

3. 字段恢复

由于设置unused之后,并不是将该列数据立即删除,而是被隐藏起来,物理上还是存在的,因此可以通过修改数据字典的方法进行恢复。

先设置OBJECT_NAME列为unused:

SQL> desc test.objectsName                                      Null? Type ----------------------------------------- -------- ---------------------------- OWNER                                              VARCHAR2(30OBJECT_NAME                                        VARCHAR2(128SUBOBJECT_NAME                                     VARCHAR2(30DATA_OBJECT_ID                                     NUMBER OBJECT_TYPE                                        VARCHAR2(19CREATED                                            DATE LAST_DDL_TIME                                      DATE TIMESTAMP                                          VARCHAR2(19STATUS                                             VARCHAR2(7TEMPORARY                                          VARCHAR2(1GENERATED                                          VARCHAR2(1SECONDARY                                          VARCHAR2(1NAMESPACE                                          NUMBER EDITION_NAME                                       VARCHAR2(30)SQL> alter table test.objects set unused column OBJECT_NAME;Table altered.SQL> desc test.objectsName                                      Null? Type ----------------------------------------- -------- ---------------------------- OWNER                                              VARCHAR2(30SUBOBJECT_NAME                                     VARCHAR2(30DATA_OBJECT_ID                                     NUMBER OBJECT_TYPE                                        VARCHAR2(19CREATED                                            DATE LAST_DDL_TIME                                      DATE TIMESTAMP                                          VARCHAR2(19STATUS                                             VARCHAR2(7TEMPORARY                                          VARCHAR2(1GENERATED                                          VARCHAR2(1SECONDARY                                          VARCHAR2(1NAMESPACE                                          NUMBER EDITION_NAME                                       VARCHAR2(30)

查看test.objects表的对象号:

SQL> select OBJ# from OBJ$ where name='OBJECTS';      OBJ#----------     88997

对象号为88997

查看test.objects表的字段号、初始字段号、字段名:

SQL> select COL#,INTCOL#,NAME from COL$ where OBJ#=88997;      COL# INTCOL# NAME---------- ---------- ------------------------------         1          1 OWNER         0          2 SYS_C00002_21052517:15:22$         2          3 SUBOBJECT_NAME         3          4 DATA_OBJECT_ID         4          5 OBJECT_TYPE         5          6 CREATED         6          7 LAST_DDL_TIME         7          8 TIMESTAMP         8          9 STATUS         9         10 TEMPORARY        10         11 GENERATED        11         12 SECONDARY        12         13 NAMESPACE        13         14 EDITION_NAME14 rows selected.

可以看到,原OBJECT_NAME列的字段号已被置为0,OBJECT_NAME后面列的字段号依次减1,OBJECT_NAME列的列名已被重置为SYS_C00002_21052517:15:22$。

查看test.objects表的字段数量:

SQL> select COLS from TAB$ where OBJ#=88997;      COLS----------        13

字段数量已由14个变为13个。

将test.objects表的字段号重新设置为初始字段号:

SQL> update COL$ set COL#=INTCOL# where OBJ#=88997;14 rows updated.SQL> commit;Commit complete.SQL> select COL#,INTCOL#,NAME from COL$ where OBJ#=88997;      COL# INTCOL# NAME---------- ---------- ------------------------------         1 1 OWNER         2 2 SYS_C00002_21052517:15:22$         3 3 SUBOBJECT_NAME         4 4 DATA_OBJECT_ID         5 5 OBJECT_TYPE         6 6 CREATED         7 7 LAST_DDL_TIME         8 8 TIMESTAMP         9 9 STATUS        10 10 TEMPORARY        11 11 GENERATED        12 12 SECONDARY        13 13 NAMESPACE        14 14 EDITION_NAME14 rows selected.

将字段数恢复为14个:

SQL> update TAB$ set COLS=COLS+1 where OBJ#=88997;1 row updated.SQL> commit;Commit complete.SQL> select COLS from TAB$ where OBJ#=88997;      COLS----------        14

将第二个字段的字段名设置成与之前相同:

update COL$ set NAME='OBJECT_NAME' where OBJ#=88997 and COL#=2;1 row updated.SQL> commit;Commit complete.SQL> select COL#,INTCOL#,NAME from COL$ where OBJ#=88997;      COL# INTCOL# NAME---------- ---------- ------------------------------         1          1 OWNER         2          2 OBJECT_NAME         3          3 SUBOBJECT_NAME         4          4 DATA_OBJECT_ID         5          5 OBJECT_TYPE         6          6 CREATED         7          7 LAST_DDL_TIME         8          8 TIMESTAMP         9          9 STATUS        10         10 TEMPORARY        11         11 GENERATED        12         12 SECONDARY        13         13 NAMESPACE        14         14 EDITION_NAME14 rows selected.

SQL> update COL$ set PROPERTY=0 where OBJ#=88997;14 rows updated.SQL> commit;Commit complete.

至此数据字典已全部改回,重启数据库生效。

SQL> shutdown immediateDatabase closed.Database dismounted.ORACLE instance shut down.SQL> startupORACLE instance started.Total System Global Area 1486495744 bytesFixed Size 2253384 bytesVariable Size 1375735224 bytesDatabase Buffers 100663296 bytesRedo Buffers 7843840 bytesDatabase mounted.Database opened.SQL> desc test.objects  Name Null? Type ----------------------------------------- -------- ---------------------------- OWNER VARCHAR2(30) OBJECT_NAME VARCHAR2(128) SUBOBJECT_NAME VARCHAR2(30) DATA_OBJECT_ID NUMBER OBJECT_TYPE VARCHAR2(19) CREATED DATE LAST_DDL_TIME DATE TIMESTAMP VARCHAR2(19) STATUS VARCHAR2(7) TEMPORARY VARCHAR2(1) GENERATED VARCHAR2(1) SECONDARY VARCHAR2(1) NAMESPACE NUMBER EDITION_NAME VARCHAR2(30)SQL> select OBJECT_NAME from test.objects where rownum<10;OBJECT_NAME--------------------------------------------------------------------------------ICOL$I_USER1CON$UNDO$C_COBJ#I_OBJ#PROXY_ROLE_DATA$I_IND1I_CDEF29 rows selected.

恢复完成。

END

更多精彩干货分享

点击下方名片关注

IT那活儿

文章转载自IT那活儿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论