Como desfragmentar tabelas no Oracle? (parte 2)
Autor: Fabio Prado | Publicado: 2017-05-26T17:43:00-03:00



Olá pessoal,


&nbsp; &nbsp; &nbsp;Este artigo é continuação de outro com o título "Como desfragmentar tabelas no Oracle (parte 1)" e nele irei abordar os seguintes tópicos:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- Como evitar ou minimizar a quantidade de LEMs em uma tabela?
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- Como identificar e eliminar as LEMs?


&nbsp; &nbsp; &nbsp;No artigo anterior expliquei os conceitos gerais sobre fragmentação de dados, conceitos sobre blocos vazios (popularmente conhecidos como "buracos") e LEMs nas tabelas, e mostrei como identificar e eliminar os "buracos" nelas. Vejamos agora os tópicos que citei no parágrafo anterior.&nbsp;





Como evitar ou minimizar a quantidade de LEMs em uma tabela?

&nbsp; &nbsp; &nbsp;Considere as dicas abaixo para evitar ou minimizar a quantidade de LEMs em uma tabela:

&nbsp; &nbsp; &nbsp;1- Configure apropriadamente os parâmetros PCTFREE e PCTUSED:

&nbsp; &nbsp; &nbsp;Uma tabela que sofre muitos UPDATEs talvez requeira um aumento no valor de PCTFREE, pois com mais espaço livre nos blocos para futuras atualizações, menor a probabilidade de criação de LEMs. Já em tabelas que sofrem apenas INSERTs e DELETEs, talvez seja melhor configurar um valor de PCTFREE menor&nbsp;(já que não é necessário reservar espaço nos blocos para futuros updates)&nbsp;que o valor padrão de 10 ou até mesmo zerá-lo. PCTUSED também poderia ser configurado para um valor menor, neste caso, mas somente se o segmento estiver configurado no modo "manual automatic segment-space management", caso contrário ele será ignorado.

&nbsp; &nbsp; &nbsp;2- Configure apropriadamente o tamanho do bloco da tabela:
&nbsp; &nbsp; &nbsp;Se os dados de uma linha de uma tabela não cabem em único bloco considere configurar um dos parâmetros DB_NK_BLOCK_SIZE de acordo com o tamanho das linhas e crie um tablespace com um tamanho de bloco igual ao do parâmetro configurado para essa tabela. Isso é bastante apropriado em ambientes OLAP. Em OLTP deve ser avaliado cuidadosamente.



Como identificar e eliminar as LEMs?




&nbsp; &nbsp; &nbsp;Para identificar e eliminar LEMs em um determinado BDs que você administra, sugiro que você execute os passos abaixo:



1- Verificação de LEMs no nível do BD:
&nbsp; &nbsp; &nbsp;É bem fácil descobrir se o BD possui LEMs em alguma tabela, basta analisar a estatística&nbsp;"table fetch continued row"&nbsp;que indica quantidade de LEMs encontradas nas consultas que já foram efetuadas no nível da sessão ou instância. Essa estatística pode ser consultada nas visões&nbsp;v$sysstat,&nbsp;v$sesstat ou v$mystat.



&nbsp; &nbsp; &nbsp;Para ver LEMs no nível da instância:&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;select value&nbsp;
&nbsp; &nbsp; &nbsp;from &nbsp; v$sysstat&nbsp;
&nbsp; &nbsp; &nbsp;where &nbsp;name like 'table fetch continued row%';

&nbsp; &nbsp; &nbsp;Para ver LEMs acessadas por cada sessão do BD:&nbsp;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;SELECT&nbsp;b.sid,&nbsp;b.value

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;FROM &nbsp; v$statname a,&nbsp;v$sesstat&nbsp;b

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;WHERE &nbsp;a.statistic# = b.statistic#

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;AND &nbsp; &nbsp;lower(a.name) = 'table fetch continued row';



&nbsp; &nbsp; &nbsp;Para ver LEMs acessadas na sua sessão:&nbsp;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;SELECT b.value

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;FROM &nbsp; v$statname a, v$mystat b

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;WHERE &nbsp;a.statistic# = b.statistic#

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;AND &nbsp; &nbsp;lower(a.name) = 'table fetch continued row';



&nbsp; &nbsp; &nbsp;Este método é uma forma mais rápida de identificar se existem LEMs sob uma visão macro do BD. Se o valor da consulta for maior que zero você já saberá que existem LEMs no BD, porém não saberá ainda em quais tabelas elas estão. Para isso, parta para o próximo passo.





2- Identificação das tabelas que possuem LEMs:


&nbsp; &nbsp; &nbsp;Para identificar as tabelas que possuem LEMs você pode criar um bloco PL/SQL com SQL dinâmico para executar o comando abaixo em cada tabela dos schemas de usuários do BD:



&nbsp; &nbsp; &nbsp;ANALYZE TABLE ECOMMERCE.PEDIDO COMPUTE STATISTICS;



&nbsp; &nbsp; &nbsp;Execute em seguida uma consulta na visão DBA_TABLES e veja o valor da coluna CHAIN_CNT. Se for maior que zero, significa que existem LEMs dentro do segmento da tabela:

&nbsp; &nbsp; &nbsp;select  blocks "Blocos Usados", chain_cnt "LEMs", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; num_rows "Total de Linhas" &nbsp; &nbsp; &nbsp;from &nbsp; dba_tables &nbsp; &nbsp; &nbsp;where &nbsp;owner = 'ECOMMERCE'&nbsp; &nbsp; &nbsp;AND &nbsp; &nbsp;table_name='PEDIDO';



&nbsp; &nbsp; &nbsp;Depois que foi identificado que a tabela possui LEMs, elimine-as através de um simples ALTER TABLE&nbsp;nome_tabela&nbsp;MOVE&nbsp;ou utilizando o pacote DBMS_REDEFINITION. O ALTER TABLE MOVE é bem mais simples, mas gera indisponibilidade, por isso, se você precisa fazer essa manutenção à quente, sem gerar indisponibilidade, sugiro a 2º opção, ou o método que vou descrever no próximo passo (meu preferido).



&nbsp; &nbsp; &nbsp;Para quem quiser aprender mais sobre DBMS_REDEFINITION, sugiro a leitura dos seguintes documentos no MOS:&nbsp;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -&nbsp;DBMS_REDEFINITION ONLINE REORGANIZATION OF TABLES (Doc ID 149564.1);


&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - How to Find Fragmentation for Tables and LOBs (Doc ID 2132004.1).







3-&nbsp;LIST CHAINED ROWS:

&nbsp; &nbsp; &nbsp;Já sabemos qual tabela tem LEMs, então agora é só executar o comando "ANALYZE TABLE nome_tabela LIST CHAINED ROWS" para que algumas informações sobre as LEMs sejam gravadas na tabela CHAINED_ROWS, que deve ser criada previamente através da execução do script $ORACLE_HOME/rdbms/admin/utlchain.sql:&nbsp;
&nbsp; &nbsp; &nbsp;ANALYZE TABLE ECOMMERCE.PEDIDO LIST CHAINED ROWS;




&nbsp; &nbsp; &nbsp;Este método é o meu preferido para identificar LEMs, pois ele grava na tabela CHAINED_ROWS os ROWIDs das LEMs, o que facilita depois o processo de eliminação delas. Fazendo um join na CHAINED_ROWS com a a tabela analisada é possível recuperar as linhas completas que estão encadeadas ou migradas, e armazená-las em uma tabela temporária qualquer que tenha a mesma estrutura da tabela analisada (criada a partir de um CTAS, por exemplo), para depois apagar as linhas da tabela original e reinseri-las novamente a partir da tabela temporária. A reinserção é bastante eficiente para eliminar este tipo de "fragmentação".
&nbsp; &nbsp;




&nbsp; &nbsp; &nbsp;Para finalizar é importante ressaltar que os procedimentos de eliminação de blocos vazios e LEMs descritos neste artigo e no artigo anterior, podem reduzir o tamanho do segmento da tabela (compactação lógica), mas não o tamanho físico do(s) datafile(s) do tablespace em que ela está alocada. Se você precisar também diminuir o tamanho deles, sugiro a leitura do artigo&nbsp;
Reorganizando o Tablespace ....



FIM &nbsp;