Упрощенное / автоматическое освобождение свободного места на диске


8

На версии Oracle 11g:

После Google не могу найти простой способ вернуть свободное место после удаления таблицы.

Я нашел много объяснений, рассказывающих, как файл данных становится фрагментированным, большой стек скучных запросов, которые вам нужно выполнить, чтобы переместить «пустое пространство» в конец файла данных (таблица за таблицей ... даже когда вы есть 200 столов!?).

Затем вам нужно уменьшить размер файла данных, «угадав», насколько вы можете его уменьшить, или вы должны точно знать, каков ваш «размер блока» ... И, наконец, вы не должны забывать «перестраивать индексы».

См. Например: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:54178027703899

и http://www.oracle-base.com/articles/misc/ReclaimingUnusedSpace.php

Существует ли простая процедура PL / SQL, которая, учитывая имя табличного пространства или имя файла данных, будет выполнять эту работу? Или любой подобный инструмент Oracle?


Интересная информация: проверьте, являются ли ваши табличные пространства «локально управляемыми» или «управляемыми каталогами». Первый, похоже, лучше обрабатывает «дефрагментирующие» файлы данных. Смотрите: orafaq.com/node/3
Морозный Z

Ответы:


5

Краткий ответ - нет . К сожалению, способ сделать это в Oracle требует «большого количества скучных запросов». Статьи, на которые вы ссылаетесь, являются одними из лучших на эту тему. Файл данных действительно фрагментируется, поэтому даже если свободное пространство находится ниже самого высокого сегмента, Oracle не будет автоматически консолидировать его, когда RESIZEбудет выполнено a .

Чтобы «дефрагментировать» табличное пространство, вам нужно переместить эти сегменты в начало файла данных, а не в конец. Для таблиц это автономный процесс, то есть таблица будет недоступна во время перемещения. Индексы можно перемещать либо в автономном режиме, либо с помощью Enterprise Edition их можно перемещать в режиме онлайн. Поскольку у вас есть окно отключения, я рекомендую вам выполнить следующие шаги.

A. Сжатие файлов данных со свободным пространством за отметкой максимальной воды. Это можно сделать следующим образом (запрос аналогичен процедуре Frosty Z):

SELECT ceil( blocks*(a.BlockSize)/1024/1024) "Current Size",
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Smallest Poss.",
   ceil( blocks*(a.BlockSize)/1024/1024) -
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Savings",
   'alter database datafile '''|| file_name || ''' resize ' || 
      ceil((nvl(hwm,1)*(a.BlockSize))/1024/1024/100)*100  || 'm;' "Command"
FROM (SELECT a.*, p.value BlockSize FROM dba_data_files a 
JOIN v$parameter p ON p.Name='db_block_size') a
LEFT JOIN (SELECT file_id, max(block_id+blocks-1) hwm FROM dba_extents GROUP BY file_id ) b
ON a.file_id = b.file_id
WHERE ceil( blocks*(a.BlockSize)/1024/1024) - ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) 
   > 100 /* Minimum MB it must shrink by to be considered. */
ORDER BY "Savings" Desc;

Б. После того, как вы сузили положение выше верхней отметки, выясните, какие табличные пространства все еще выиграют от перемещения сегментов.

SELECT DISTINCT tablespace_name FROM
(      
    SELECT tablespace_name, block_id + blocks LastBlock,
       lead(block_id) OVER (PARTITION BY File_ID 
          ORDER BY tablespace_name, file_id, block_id) NextBlock
       FROM dba_free_space 
) WHERE LastBlock <> NextBlock AND NextBlock IS NOT NULL;

C. Для каждого из этих табличных пространств определите, какие сегменты необходимо переместить. (Замените USERS именем вашего табличного пространства или присоедините его к предыдущему запросу)

SELECT distinct de.segment_name
FROM dba_extents de
JOIN
(
   SELECT tablespace_name, file_id, MIN(block_id) LowestFreeBlock
   FROM dba_free_space
   WHERE tablespace_name = 'USERS'
  GROUP BY tablespace_name, file_id
) dfs ON dfs.tablespace_name = de.tablespace_name AND dfs.file_id = de.file_id
WHERE de.tablespace_name = 'USERS'
AND de.block_id > dfs.LowestFreeBlock;

D. Переместите каждую таблицу и перестройте индексы и статистику.

E. повторите шаг A.

Я только что построил большинство этих запросов, так что вы захотите тщательно протестировать их перед использованием. Я полагаю, вы могли бы создать процедуру, которая использовалась бы EXECUTE IMMEDIATEдля создания фактических операторов для динамического выполнения, но поскольку запросы будут получать ORA-08103: объект больше не существует, пока выполняется перемещение, я думаю, что лучше контролировать этот процесс вручную, даже если если это действительно означает немного больше времени / усилий.


3

Частичное решение, вдохновленное этой страницей :

Он не реорганизует свободное пространство, но автоматически обнаруживает доступное свободное пространство в конце файлов данных и печатает правильные команды «ИЗМЕНИТЬ».

DECLARE
    BLKSIZE INTEGER;

BEGIN
    SELECT VALUE INTO BLKSIZE FROM V$PARAMETER WHERE NAME = 'db_block_size';

    FOR INDEX_ROW IN (
      SELECT 'ALTER DATABASE DATAFILE ''' || FILE_NAME || ''' RESIZE ' || CEIL( (NVL(HWM,1)*BLKSIZE)/1024/1024 ) || 'M;' SHRINK_DATAFILES FROM DBA_DATA_FILES DBADF,
            (SELECT FILE_ID, MAX(BLOCK_ID+BLOCKS-1) HWM FROM DBA_EXTENTS GROUP BY FILE_ID ) DBAFS
            WHERE DBADF.FILE_ID = DBAFS.FILE_ID(+) AND CEIL(BLOCKS*BLKSIZE/1024/1024)- CEIL((NVL(HWM,1)* BLKSIZE)/1024/1024 ) > 0
    ) LOOP
        DBMS_OUTPUT.PUT_LINE(INDEX_ROW.SHRINK_DATAFILES);
    END LOOP;
END;

2

Прежде чем пытаться вообще сжимать файлы данных, спросите себя: собираетесь ли вы снова создавать новые сегменты внутри связанного табличного пространства, когда-нибудь в ближайшем будущем? Если да, то нет смысла сокращаться. Пространство просто будет повторно использовано для ваших новых сегментов, и вы сэкономите себе и системе много сил, оставив все как есть.


2

После нескольких дней серфинга в Google я нашел самый простой и понятный пример восстановления свободного пространства в табличном пространстве после удаления. надеюсь, это поможет

Ссылка: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html

решение:

ALTER TABLE MOVE demo

Давайте создадим таблицу с 9999 строками, каждая размером около 1 КБ:

SQL> create table t (x char(1000) default 'x' primary key);
Table created.
SQL> insert /*+ append nologging */ into t(x) select rownum from all_objects where rownum < 10000;
9999 rows created.
SQL> commit;
Commit complete.

Для таблицы выделено 29 экстентов, в общей сложности 14,6M:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

Давайте удалим ВСЕ строки:

SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.

Теперь - «сюрприз» - таблица все еще использует те же экстенты:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

Почему ? Потому что даже если вы удалите все строки таблицы, High Water Mark не будет уменьшен - он никогда не будет уменьшен, чтобы обеспечить максимальный параллелизм (Oracle абсолютно серьезно относится к максимизации параллелизма, то есть производительности и масштабируемости; это главная причина его успеха в корпоративных приложениях).

Распределение неиспользуемого пространства (= пространство над HWM) мало помогает (так как над HWM не так много неиспользуемого пространства):

SQL> alter table t deallocate unused;
Table altered.
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 13959168

Теперь давайте переместим таблицу, что по сути означает клонировать таблицу (включая триггеры, ограничения и т. Д.), Перенести строки, удалить «старую» таблицу и переименовать новую - все сделано ядром, так что это супер-безопасно даже в случае отказа машины / сервера:

SQL> alter table t move;
Table altered.

Теперь у нас есть только начальный экстент:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536

Предупреждение: обычно случается, что многие / все индексы в таблице НЕПРАВИЛЬНЫ после перемещения (не в этом случае, но я использую 9.2.0.4, последний выпуск, который, вероятно, оптимизировал процесс в случае полностью пустых таблиц ):

SQL> col table_name form a30
SQL> col index_name form a30
SQL> set lines 123 
SQL> select table_name, index_name, status from user_indexes where table_name='T';

TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ ------------------------
T SYS_C002573 VALID

Если STATUS не VALID, вы можете просто перестроить вручную индекс (ы):

SQL> alter index SYS_C002573 rebuild;
Index altered.

Или вы можете автоматизировать весь процесс:

set serveroutput on size 100000
begin
for n in (select index_name from user_indexes where status <> 'VALID') loop
dbms_output.put_line ('rebuilding ' || n.index_name);
execute immediate 'alter index ' || n.index_name || ' rebuild';
end loop;
end;
/

В качестве примера давайте вручную установим индекс на UNUSABLE:

SQL> alter index SYS_C002573 unusable;
Index altered.

SQL> set serveroutput on size 100000
SQL> begin
2 for n in (select index_name from user_indexes where status <> 'VALID') loop
3 dbms_output.put_line ('rebuilding ' || n.index_name);
4 execute immediate 'alter index ' || n.index_name || ' rebuild';
5 end loop;
6 end;
7 /
rebuilding SYS_C002573

PL/SQL procedure successfully completed.

HTH Альберто


1

Как было сказано ранее, вам придется переместить все 200+ таблиц в этом табличном пространстве, чтобы освободить место в вашем файле данных, а затем изменить размер, чтобы освободить пространство. Но вместо выполнения всех этих запросов 12c Enterprise manager выполняет эту задачу. Вам нужно будет перейти к базе данных Home> Storage> Tablespace. Выберите табличное пространство, над которым вы хотите работать, и нажмите «Реорганизовать». Это даст возможность просмотреть операторы SQL, которые должны быть выполнены. Вы можете либо взять их копию и запустить ее самостоятельно, либо запланировать работу в EM.

Он фактически создает другое табличное пространство, перемещает все объекты в новое табличное пространство, перестраивает индексы и удаляет объекты из старого табличного пространства.

Есть несколько недостатков, о которых я могу подумать. Это должно быть сделано в непиковые часы, иначе произойдет ошибка, сообщающая, что ресурс занят. К файлу данных (а не к табличному пространству) к его имени будет добавлен «reorg» ближе к концу.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.