AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 6593
Accepted
Frosty Z
Frosty Z
Asked: 2011-10-08 05:12:15 +0800 CST2011-10-08 05:12:15 +0800 CST 2011-10-08 05:12:15 +0800 CST

Recuperação de espaço em disco livre de arquivo de dados simplificado/automatizado

  • 772

No Oracle versão 11g:

Depois de pesquisar no Google, não consigo encontrar uma maneira simples de recuperar espaço livre após excluir uma tabela.

Encontrei muitas explicações, dizendo como o arquivo de dados fica fragmentado, a grande pilha de consultas chatas que você precisa executar para mover o "espaço vazio" no final do arquivo de dados (tabela por tabela ... mesmo quando você tem 200 mesas!?).

Então você tem que reduzir o tamanho do arquivo de dados "adivinhando" em quanto você pode reduzi-lo, ou você deve saber exatamente qual é o seu "tamanho de bloco"... E finalmente você não deve esquecer de "reconstruir os índices".

Veja por exemplo: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:54178027703899

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

Existe um procedimento PL/SQL simples que, dado um nome de tablespace ou nome de arquivo de dados, seria para esse trabalho? Ou alguma ferramenta semelhante da Oracle?

oracle oracle-11g
  • 5 5 respostas
  • 39710 Views

5 respostas

  • Voted
  1. Best Answer
    Leigh Riffel
    2011-10-08T08:05:16+08:002011-10-08T08:05:16+08:00

    A resposta curta é Não . Infelizmente, a maneira de fazer isso no Oracle requer a "grande pilha de consultas chatas". Os artigos aos quais você vinculou são algumas das melhores informações disponíveis sobre o assunto. O arquivo de dados realmente se torna fragmentado, de modo que, mesmo que exista espaço livre abaixo do segmento mais alto, o Oracle não o consolidará automaticamente quando a RESIZEfor concluído.

    Para "desfragmentar" o tablespace, você precisa mover esses segmentos para o início do arquivo de dados e não para o final. Para mesas, este é um processo offline, o que significa que a mesa não estará disponível enquanto a movimentação estiver ocorrendo. Os índices podem ser movidos offline ou com Enterprise Edition eles podem ser movidos online. Como você tem uma janela de interrupção, recomendo que você siga estas etapas.

    A. Reduza os arquivos de dados com espaço livre além do limite máximo. Isso pode ser feito da seguinte forma (a consulta é semelhante ao procedimento do 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;
    

    B. Depois de reduzir as coisas acima da marca d'água, descubra quais tablespaces ainda se beneficiariam com a movimentação de segmentos.

    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. Para cada um desses tablespaces, determine quais segmentos precisam ser movidos. (Substitua USERS pelo nome do seu tablespace ou una-o com a consulta anterior)

    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. Mova cada tabela e reconstrua os índices e estatísticas.

    E. Repita a etapa A.

    Acabei de construir a maioria dessas consultas, então você vai querer testá-las completamente antes de usar. Suponho que você poderia criar um procedimento que usaria EXECUTE IMMEDIATEpara criar as instruções reais para executar dinamicamente, mas como as consultas receberão ORA-08103: O objeto não existe mais enquanto a movimentação está em andamento, acho melhor controlar esse processo manualmente mesmo se isso significar um pouco mais de tempo/esforço.

    • 5
  2. Frosty Z
    2011-10-08T06:03:44+08:002011-10-08T06:03:44+08:00

    Solução parcial inspirada nesta página :

    Ele não reorganiza o espaço livre, mas detecta automaticamente o espaço livre disponível no final dos arquivos de dados e imprime os comandos 'RESIZE' apropriados.

    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;
    
    • 3
  3. Uwe Hesse
    2011-10-11T02:22:46+08:002011-10-11T02:22:46+08:00

    Antes de tentar reduzir os arquivos de dados, pergunte a si mesmo: você vai criar novos segmentos novamente dentro do espaço de tabela associado em algum momento em um futuro não tão distante? Se sim, não adianta diminuir. O espaço será reutilizado para seus novos segmentos e você economiza muito esforço para si mesmo e para o sistema, deixando-o como está.

    • 2
  4. vishal0108
    2013-04-09T04:36:14+08:002013-04-09T04:36:14+08:00

    Depois de navegar no google por dias, encontrei o exemplo mais simples e claro para recuperar o espaço livre no tablespace após a exclusão. Eu espero que isso ajude

    Link: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html

    solução:

    ALTER TABLE MOVE demo
    

    Vamos criar uma tabela com 9999 linhas, cada uma com cerca de 1k:

    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.
    

    A tabela tem 29 extensões alocadas a ela, para um total de 14,6M:

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

    Vamos deletar TODAS as linhas:

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

    Agora- "surpresa" - a tabela ainda usa as mesmas extensões:

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

    Por quê ? Porque mesmo que você exclua todas as linhas da tabela, o High Water Mark não é diminuído - ele nunca é diminuído, para permitir a simultaneidade máxima (Oracle leva a sério a maximização da simultaneidade, ou seja, desempenho e escalabilidade; é a principal razão por trás de seu sucesso em aplicativos corporativos).

    Desalocar o espaço não utilizado (= espaço acima do HWM) não ajuda muito (já que não há muito espaço não utilizado acima do 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
    

    Agora, vamos MOVER a tabela, que em essência significa clonar a tabela (incluindo gatilhos, restrições e assim por diante), transferir as linhas, descartar a tabela "antiga" e renomear a nova - tudo feito pelo kernel, tão super seguro mesmo em caso de falha da máquina/servidor:

    SQL> alter table t move;
    Table altered.
    

    Agora, temos agora apenas a extensão inicial alocada:

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

    Advertência: normalmente acontece que muitos/todos os índices na tabela ficam INUSÁVEIS após a mudança (não neste caso, mas estou executando a versão 9.2.0.4, a versão mais recente, que provavelmente otimizou o processo no caso de tabelas totalmente vazias ):

    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
    

    Se STATUS não fosse VALID, você poderia simplesmente reconstruir manualmente o(s) índice(s):

    SQL> alter index SYS_C002573 rebuild;
    Index altered.
    

    Ou você pode automatizar todo o processo:

    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;
    /
    

    Como exemplo, vamos definir manualmente o índice para 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 Alberto

    • 2
  5. Srikanthan
    2015-07-21T12:45:36+08:002015-07-21T12:45:36+08:00

    Como dito anteriormente, você terá que mover todas as mais de 200 tabelas nesse tablespace para liberar algum espaço em seu arquivo de dados e, em seguida, redimensionar para recuperar o espaço. Mas em vez de executar todas essas consultas, o 12c Enterprise Manager faz essa tarefa. Você terá que navegar para Database Home > Storage > Tablespace. Selecione o tablespace no qual deseja trabalhar e clique em Reorganizar. Ele dará uma opção para visualizar as instruções SQL que estão prestes a ser executadas. Você pode fazer uma cópia deles e executá-lo você mesmo ou agendar um trabalho no EM.

    Na verdade, ele cria outro tablespace, move todos os objetos para o novo tablespace, reconstrói os índices e remove os objetos do tablespace antigo.

    Há um par de desvantagens que posso pensar. Isso deve ser feito fora do horário de pico, caso contrário, ocorrerá um erro dizendo que o recurso está ocupado. O arquivo de dados (não o tablespace) terá "reorg" adicionado ao seu nome, no final.

    • 1

relate perguntas

  • Backups de banco de dados no Oracle - Exportar o banco de dados ou usar outras ferramentas?

  • ORDER BY usando prioridades personalizadas para colunas de texto

  • Interface sqlplus confortável? [fechado]

  • Como encontrar as instruções SQL mais recentes no banco de dados?

  • Como posso consultar nomes usando expressões regulares?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como você mostra o SQL em execução em um banco de dados Oracle?

    • 2 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Posso ver Consultas Históricas executadas em um banco de dados SQL Server?

    • 6 respostas
  • Marko Smith

    Como uso currval() no PostgreSQL para obter o último id inserido?

    • 10 respostas
  • Marko Smith

    Como executar o psql no Mac OS X?

    • 11 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Marko Smith

    Passando parâmetros de array para um procedimento armazenado

    • 12 respostas
  • Martin Hope
    Manuel Leduc Restrição exclusiva de várias colunas do PostgreSQL e valores NULL 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler Quando uma chave primária deve ser declarada sem cluster? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - Qual é melhor como chave primária? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick Como posso otimizar um mysqldump de um banco de dados grande? 2011-01-04 13:13:48 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve