sql—如何摆脱空但巨大的lob列?

tjvv9vkg  于 2021-07-26  发布在  Java
关注(0)|答案(1)|浏览(347)

我们有一个lob列的表,它是空的,因为内容已经转移到其他地方(另一列)。但是,lob段仍然占用300gb,我无法摆脱它。
下面是一个简单的例子:

CREATE TABLE t (id NUMBER, c CLOB) 
  LOB (c) STORE AS BASICFILE (DISABLE STORAGE IN ROW RETENTION NONE);
INSERT INTO t SELECT object_id, object_name FROM all_objects;
COMMIT;

UPDATE T SET c=NULL;
COMMIT;

现在,lob是空的,但存储仍占用500 mb:

SELECT s.bytes/1024/1024 as mb 
  FROM user_lobs 
  JOIN dba_segments s using (segment_name);

MB
528

在最简单的例子中, ALTER TABLE MOVE 工作,但不与真正的表,因为它太大,并运行到各种oracle错误。在线重新定义也不起作用,因为底层数据类型是二进制xml。expdp/impdp生产时间过长。
我简直不敢相信要收回一个完全空的列的空间是不可能的。
请问谁能帮忙?

z8dt9xmd

z8dt9xmd1#

作为删除和重新添加列的替代方法,可以使用 shrink space 条款:

ALTER TABLE t MODIFY LOB (c) (SHRINK SPACE);

db<>小提琴,它是18摄氏度,但应该工作在11克了(后来:是的,它在11gr2和 retention none 无论如何省略;不过,sql fiddle不喜欢它。)
底层数据类型是二进制xml
错过了这个细节,但它仍然有效;您只需要额外的一步就可以找到备份xmltype列的隐藏blob列,如下所示。我已经成功了 alter 动态只是为了在运行中获取它,但是如果您可以手动找到它,那么您可以自己将它插入到语句中显然:

DECLARE
  l_name USER_TAB_COLUMNS.COLUMN_NAME%TYPE;
  l_stmt VARCHAR2(100);
BEGIN
  select column_name
  into l_name
  from user_tab_cols 
  where 
    table_name = 'T' and hidden_column = 'YES'
    and
    column_id = (
        select column_id 
        from user_tab_cols 
        where table_name = 'T' and column_name = 'X'
    );

  l_stmt := 'ALTER TABLE t MODIFY LOB ("' || l_name || '") (SHRINK SPACE)';
  dbms_output.put_line(l_stmt);
  execute immediate l_stmt;
END;
/

db<>小提琴
可能值得注意的是,这与 basicfile 存储,如您的最小演示所示,但可能无法与 securefile 存储—至少有一部分时间抛出ora-10635:无效的段或表空间类型。

相关问题