oracle 大表在线删除列操作(alter table table_name set unused )
在某些情况下业务建的表某些列没有用到,需要进行删除,但是如果是数据量很大的大表,直接 alter table table_name drop column column_name;这种方法删除,那么将出现TM表锁,业务有可能hang住,所以不能这样子操作;Oracle 8i 引入了从表中删除列的能力。在此之前,有必要删除整个表并重建它。可以将列标记为未使用(逻辑删除)或完全删除(物理删除),下面介绍逻辑删除和物理删除。
一.逻辑删除
在大表上,物理删除列的过程非常耗时且耗费资源。决定从逻辑上删除最合适。实际上并未删除目标列数据或恢复这些列占用的磁盘空间。但是,标记为未使用的列不会显示在查询或数据字典视图中,并且会删除其名称,以便新列可以重用该名称。列上定义的所有约束、索引和统计信息也将被删除。
语法:
alter table table_name set unused (column_name) ONLINE; --加上ONLINE,业务不阻塞
alter table table_name set unused (column_name1, column_name2);
注意:set unused 语句是不可逆的操作,意思就是不能进行recover,除非你有备份。
完成此操作后,将不再看到这些列。如果以后您有时间物理删除列,可以使用以下方法完成。
alter table table_name drop unused columns ONLINE ;语句是对未使用的列唯一允许的操作。它从表中物理删除未使用的列并回收磁盘空间。
alter table table_name drop unused columns checkpoint XX;该子句导致在处理指定数量的行后应用检查点,在本例中为 1000。检查点减少了删除列操作期间累积的undo日志量,以避免undo空间的潜在耗尽。
DBA_UNUSED_COL_TABS 视图可用于查看每个表未使用的列数。
例如我需要删除user_order_detail 的DEL_IND,DEL_USER_ID,DEL_DTT这三列。
select count(*) from user_order_detail ;
alter table user_order_detail set unused (DEL_IND,DEL_USER_ID,DEL_DTT); --这个执行是秒级别的非常快;建议删除后有触发器的涉及到这几列的重建触发器,oracle19-20c有bug,21c修复次BUG。
select * from DBA_UNUSED_COL_TABS;
alter table user_order_detail drop unused columns checkpoint 1000; --这个执行看你的数据量,物理删除比较慢。从表中物理删除未使用的列并回收磁盘空间。
可以想象,才200多万数据删除3列这么久,如果不是采用set unused 这种方法删除,直接物理删除千万甚至亿级别的数据,业务响应将是多么的可怕。
二.物理删除
要物理删除列,您可以使用以下语法之一,具体取决于您希望删除单个列还是多个列。
alter table table_name drop column column_name; alter table table_name drop (column_name1, column_name2);
同时,从表中删除一列将导致该表中所有未使用的列同时被删除(即有set unused 的列将被删除)。
大表一般不用这种方法删除,对业务影响太严重,小表就可以这么操作,在及时性要求不高的情况下。
最后
如果删除列之后,即:
alter table table_name set unused (column_name);有进行alter table table_name move;操作,至于move 和shrink操作的影响以及区别我在索引帖子里面已经说到过。
三.总结一下set unused
1.指定SET
UNUSED
将一列或多列标记为未使用。对于内部堆组织表,指定此子句实际上不会从表中的每一行中删除目标列。它不会恢复这些列使用的磁盘空间。因此,响应时间比执行DROP
子句时要快。
当您为外部表中的列指定此子句时,该子句将透明地转换为ALTER
TABLE
...DROP
COLUMN
语句。这样做的原因是,对外部表的任何操作都是元数据操作,因此两个命令的性能没有区别。
2.用标列的所有表UNUSED
中的数据字典视图USER_UNUSED_COL_TABS
,DBA_UNUSED_COL_TABS
和ALL_UNUSED_COL_TABS
。
未使用的列被视为已删除,即使它们的列数据仍保留在表行中。一列被标记后UNUSED
,将无法访问该列。SELECT
查询不会检索未使用的列数据。此外,标记的列的名称和类型
UNUSED
在 期间不会显示DESCRIBE
,可以向表中添加一个与未使用的列同名的新列。
3.实际删除这些列之前,它们将继续计入单个表中 1000 列的绝对限制。但是,与所有 DDL 语句一样,不能回滚此子句的结果。不能发出SET
USED
对应物来检索您拥有的列SET
UNUSED
。此外,如果您将一LONG
列标记为UNUSED
,则LONG
在您实际删除未使用的LONG
列之前,您无法向表中添加另一列。
4.建议加上ONLINE关键字,在线业务很重要,不会阻塞(非阻塞代表dml业务操作没影响(除了删除的列),SET UNUSED就会给表加上锁,ONLINE不影响其他DML);
如果使用ONLINE
关键字,以下操作现在是非阻塞:
ALTER TABLE table-name DROP CONSTRAINT contraint-name ONLINE;
ALTER TABLE table-name SET UNUSED (column-list) ONLINE;
DROP INDEX index-name ONLINE;
ALTER INDEX index-name UNUSABLE ONLINE;
ALTER TABLE table_name MOVE PARTITION partition-name ONLINE ...;
ALTER TABLE table_name MOVE SUBPARTITION partition-name ONLINE ...;
以下操作在没有ONLINE
关键字的情况下是非阻塞的。
ALTER INDEX index-name INVISIBLE;
ALTER INDEX index-name VISIBLE;