Как известно, от удаления данных в таблице она совсем не всегда "сжимается", а потому бывает, что в базе много невысвобожденного свободного места. Соответствующий отчет по таблицам есть в оптимизаторе, но разберем по основному источнику таких проблем - LOB-сегментам. Итак, для начала выведем список сегментов по убыванию размера
SQL код:
SELECT l.table_name,
L.COLUMN_NAME,
s.segment_name,
S.TABLESPACE_NAME,
l.owner,
round(s.bytes / 1024 / 1024 / 1024) AS "GB"
FROM dba_lobs l, dba_segments s
WHERE s.segment_name = l.segment_name
AND s.owner = l.owner
AND s.segment_type = 'LOBSEGMENT'
ORDER BY bytes DESC;
и, в зависимости от полученных результатов, можно уточнить занятое место каждым конкретным сегментом
SQL код:
DECLARE
TOTAL_BLOCKS NUMBER;
TOTAL_BYTES NUMBER;
UNUSED_BLOCKS NUMBER;
UNUSED_BYTES NUMBER;
LAST_USED_EXTENT_FILE_ID NUMBER;
LAST_USED_EXTENT_BLOCK_ID NUMBER;
LAST_USED_BLOCK NUMBER;
BEGIN
DBMS_SPACE.unused_space ('&OWNER',
'&SEGMENT_NAME',
'LOB',
TOTAL_BLOCKS,
TOTAL_BYTES,
UNUSED_BLOCKS,
UNUSED_BYTES,
LAST_USED_EXTENT_FILE_ID,
LAST_USED_EXTENT_BLOCK_ID,
LAST_USED_BLOCK);
DBMS_OUTPUT.put_line ('SEGMENT_NAME = <LOB SEGMENT NAME>');
DBMS_OUTPUT.put_line ('-');
DBMS_OUTPUT.put_line ('TOTAL_BLOCKS = ' || TOTAL_BLOCKS);
DBMS_OUTPUT.put_line ('TOTAL_BYTES = ' || TOTAL_BYTES);
DBMS_OUTPUT.put_line ('TOTAL_MB = ' || TOTAL_BYTES / 1024 / 1024);
DBMS_OUTPUT.put_line ('UNUSED_BLOCKS = ' || UNUSED_BLOCKS);
DBMS_OUTPUT.put_line ('UNUSED BYTES = ' || UNUSED_BYTES);
DBMS_OUTPUT.put_line ('UNUSED MB = ' || UNUSED_BYTES / 1024 / 1024);
DBMS_OUTPUT.put_line (
'LAST_USED_EXTENT_FILE_ID = ' || LAST_USED_EXTENT_FILE_ID);
DBMS_OUTPUT.put_line (
'LAST_USED_EXTENT_BLOCK_ID = ' || LAST_USED_EXTENT_BLOCK_ID);
DBMS_OUTPUT.put_line ('LAST_USED_BLOCK = ' || LAST_USED_BLOCK);
END;
/
оцениваем результаты. Если много UNUSED, то, если не планируется их в ближайшее время занять, можно отобрать их командой, которая откидывает пустое место в хвосте таблицы
SQL код:
ALTER TABLE &TABLE_NAME MODIFY LOB (&COLUMN_NAME) (DEALLOCATE UNUSED);
однако, иногда данные рассредоточены по всей таблице россыпью и, например, в 2Тб LOB в самом хвосте несколько килобайт, которые не дают половину свободного места высвободить. На этот случай можно выполнить команду
SQL код:
ALTER TABLE &TABLE_NAME MODIFY LOB (&COLUMN_NAME) (SHRINK SPACE COMPACT CASCADE);
Обратите внимание, что эта операция блокирующая и занимает много времени, поэтому в рабочее время ее запускать нельзя.
Как вариант можно перенести весь LOB в отдельное табличное пространство.
SQL код:
ALTER TABLE &TABLE_NAME MOVE LOB (&SEGMENT_NAME) STORE AS (TABLESPACE &NEW_TABLESPACE);