Как избавиться от пустого, но огромного столбца LOB? - PullRequest
2 голосов
/ 18 июня 2020

У нас есть таблица со столбцом LOB, которая пуста, поскольку содержимое было перенесено в другое место (другой столбец). Однако сегмент LOB по-прежнему занимает 300 ГБ, и я не могу от него избавиться.

Вот минимальный пример:

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 МБ:

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

MB
528

В минимальном примере ALTER TABLE xxx MOVE работает, но не с реальной таблицей, так как она слишком велика и вызывает различные ошибки Oracle. Онлайн-переопределение также не работает, поскольку базовый тип данных - BINARY XML. Expdp / impdp занимает слишком много времени для производства.

Я просто не могу поверить, что невозможно вернуть пространство полностью пустого столбца.

Кто может помочь, пожалуйста?

1 Ответ

1 голос
/ 19 июня 2020

В качестве альтернативы удалению и повторному добавлению столбца вы можете использовать предложение shrink space :

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

db <> fiddle , которое 18 c, но должно работать и в 11g. (Позже: да, это есть в 11gR2 с опущенным retention none; SQL Fiddle это не нравится.)

базовый тип данных - BINARY XML

Пропустил эту деталь, но она все еще работает; вам просто нужен дополнительный шаг, чтобы найти скрытый столбец BLOB, поддерживающий столбец XMLType, , как показано здесь . Я сделал alter Dynami c, чтобы подобрать его на лету, но если вы можете найти его вручную, вы можете просто вставить его в оператор, очевидно:

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 <> fiddle

Вероятно, стоит отметить, что это работает с хранилищем basicfile, как показано в вашей минимальной демонстрации, но может не работать с хранилищем securefile - по крайней мере, иногда который выдает ORA-10635: Неверный тип сегмента или табличного пространства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...