Olá pessoal!

No artigo de hoje falarei sobre um assunto que entendo como uma extensão do artigo Recriação de índices - Rebuild Index que escrevi tempos atrás.

Bom, o assunto é como efetuar uma reorganização dos dados de uma tabela em um banco de dados Oracle. Uma tabela pode se apresentar fragmentada, ou seja, com espaços não utilizados entre os espaços usados pela tabela.

Li um artigo bastante interessante, onde o autor, Mohammad, afirma que existem quatro formas de se reorganizar tabelas fragmentadas:
1) alter table ... move + rebuild indexes
2) export / truncate / import
3) create table as select
4) dbms_redefinition

No post de hoje vamos falar sobre a primeira alternativa.

Para isso vamos criar uma tabela de teste, inserir dados e manipula-los com o objetivo de criarmos lacunas de espaços na tabela. depois vamos realizar uma reorganização dos dados do objeto visando o ganho de espaço, um melhor plano de execução das consultas contra a tabela, além de uma organização melhor dos dados.

Primeiro vamos criar a tabela conforme script abaixo:

CREATE TABLE tbl_reorg
(
   codigo      NUMBER (8) NOT NULL,
   descricao   VARCHAR2 (100) NOT NULL
);

Agora vamos popular a tabela:

BEGIN
   FOR i IN REVERSE 1 .. 1000000
   LOOP
      INSERT INTO tbl_reorg (codigo, descricao) VALUES (i, 'registro da posição: ' || i);
   END LOOP;
   COMMIT;
END;


Verificando o tamanho da tabela após a inserção dos dados com o script abaixo. A projeção dos dados pode ser vista na figura 1.
SELECT SEGMENT_NAME, ROUND (SUM (bytes) / 1024 / 1024, 2) size_mb
    FROM dba_segments
   WHERE segment_name = 'TBL_REORG'
GROUP BY SEGMENT_NAME;

Figura 1: Tamanho da tabela TBL_REORG. (Fonte: autoria própria)

Vamos coletar as estatísticas da tabela pois como pode ser observado pela consulta abaixo, não existem dados estatísticos sobre o objeto.

SELECT owner,
       table_name,
       blocks,
       empty_blocks,
       num_rows,
       TO_CHAR (last_analyzed, 'DD-MM-RRRR HH24:MI:SS') AS "ANALYZE"
  FROM dba_tables
 WHERE table_name = 'TBL_REORG';

O script abaixo coleta as estatísticas da tabela.
exec dbms_stats.gather_table_stats (ownname=>'HOUSEWORK',tabname=>'TBL_REORG',estimate_percent=>30,method_opt=>'FOR ALL COLUMNS SIZE AUTO',degree=>6);

Vale lembrar que existem outras formas de coleta de estatísticas. Falei um pouco sobre isso no artigo Estatísticas no banco de dados Oracle.

Agora vamos apagar alguns dados para gerar os espaços em branco na tabela.
delete from tbl_reorg where codigo between 10000 and 20000;
delete from tbl_reorg where codigo between 50000 and 200000;
delete from tbl_reorg where codigo between 400000 and 700000;
delete from tbl_reorg where codigo > 900000;
commit;

Vamos verificar o tamanho da tabela após algumas exclusões. O resultado pode ser visto na figura 2.
SELECT SEGMENT_NAME, ROUND (SUM (bytes) / 1024 / 1024, 2) size_mb
    FROM dba_segments
   WHERE segment_name = 'TBL_REORG'
GROUP BY SEGMENT_NAME;

Figura 2: Tamanho da tabela TBL_REORG após exclusão de alguns registros. (Fonte: autoria própria)
Bom...

Para resolvermos esse problema de fragmentação, basta reconstruir o mapa binário da tabela, para isso vamos usar o comando MOVE.

Não vamos mover a tabela para outra tablespace, vamos move-la na própria tablespace com o script abaixo:
ALTER TABLE tbl_reorg MOVE;

Verificando novamente o tamanho da tabela,  se tem o resultado exibido na figura 3.

Figura 3: Tamanho da tabela TBL_REORG após exclusão de dados e MOVE. (Fonte: autoria própria)
Após a execução do MOVE, a tabela foi reorganizada e o tamanho da tabela caiu de 42MB para 19MB, fazendo apenas uma reconstrução dos extents da tabela.

É interessante também realizar uma nova coleta das estatísticas da tabela após o MOVE, para que seja "traçado" um plano de execução mais otimizado de consultas contra o objeto.

exec dbms_stats.gather_table_stats (ownname=>'HOUSEWORK',tabname=>'TBL_REORG',estimate_percent=>30,method_opt=>'FOR ALL COLUMNS SIZE AUTO',degree=>6);

Pois é pessoal...

Esse foi um dos métodos para resolver o problema da fragmentação de uma tabela no banco de dados, vale lembrar que essa situação pode causar perda de performance em um sistema de banco de dados então vale a pena ter um cuidado especial sobre o assunto.

Bom, é isso aí!

Até a próxima!

Referências:

Reis, Bruno - How to do reorg in a table in Oracle Database / Como fazer reorg em uma tabela no Banco de Dados Oracle. Disponível em: http://brunors.com/how-to-do-reorg-in-a-table-in-oracle-database-como-fazer-reorg-em-uma-tabela-no-banco-de-dados-oracle/. Acessado: 29/07/2013.

Almeida, Rodrigo - Entendendo a Marca d’água e fragmentação de tabelas. Disponível em : http://profissionaloracle.com.br/blogs/rodrigoalmeida/2008/10/07/entendendo-a-marca-dagua-e-fragmentacao-de-tabelas/. Acessado: 29/07/2013.

Taj, Mohammad - Table Fragmentation. Disponível em: http://dbataj.blogspot.com.br/2007/07/table-fragmentation.html. Acessado: 29/07/2013.