quinta-feira, 17 de dezembro de 2009

CHAINED ROWS

Opa! Como estamos hoje? Espero que bem.
Estou aqui para trocar uma idéia com vocês sobre um assunto que eu particularmente “NUNCA”, ouvi e nem vi pelos lugares que passei, os analistas, desenvolvedores e até mesmo DBA’s comentando. Porém esse assunto sempre me chamou atenção desde que eu iniciei minhas atividades como DBA, visto que nessa época tudo que mais se quer é fazer todo e qualquer tipo de teste e de implementações de recursos para otimizar e consequentemente mostrar serviço. Mas nessa época eu humildemente um DBA Jr. fui vetado, pois bem, hoje acredito que posso arriscar bater um papo sobre este assunto que acredito ser deveras interessantes, não só para os mais experientes como também para aqueles que desejam agregar mais conhecimentos sobre Oracle e assuntos nem sempre tão abordados.
Vamos lá então!?!

CHAINED ROWS ( ou Linhas Encadeadas)


CONCEITO : Trata-se das linhas divididas entre blocos diversos, causando um aumento da linha de acordo com as atualizações dessas linhas.


Bom, mas para que fique mais claro, precisamos entender onde exatamente se encaixa esse tipo de atividade, e a qual conceito esta intimamente ligada.

Estamos falando de FRAGMENTAÇÃO. Ora, fragmentação é coisa de disco rigido ( Hard Disk) e é mais coisa de sistema operacional e não de Banco.Não é? Errado, as fragmentações também ocorrem no Oracle , e como tudo que é fragmentado afetam diretamente o bom andamento e a boa continuidade das atividades diárias do seu Banco de Dados.

Vamos entender melhor o que é FRAGMENTAÇÃO e alguns de seus tipos:

Na tentativa de definir de maneira clara e objetiva o que seria fragmentação, podemos encontrar várias definições, mais ao meu ver a que mais se adequa ao termo é, “distribuição de blocos de maneira não contigua no banco de Dados, impossibilitando uma leitura integra, e forçando o Banco de dados a ter que praticamente buscar os blocos que precisam serem lidos.”


Não precisamos nem dizer que, é bem melhor eu ler 100 blocos continuamente do que eu ter que ler de 20 em 20 esparsamente, demandaria mais tempo e custaria mais recursos para gerar essa leitura.


Dentre os tipos mais famosos e mais problematicos encontramos :

FRAGMENTAÇÃO DE TABLESPACE: ocorre quando o freespace dentro de um Tablespace em especifico se encontra fragmentado em pequenos pedaços, ao invés de ser um único pedaço livre, oq ue faz com que as novas requisições de alocação de extents não encontrem um espaço continuo suficiente para realizar a tarefa. De certa maneira isso pode ser evitado controlando e definindo de maneira lógica e objetiva as clausulas de STORAGE, neste caso em particular estamos falando do PCTINCREASE, que deve ser definido como zero.

Como definir então esse PCTINCREASE ? Simples, por meio de dois comandos, digo 2 comandos porque isso se aplica tanto a INDICES quanto a TABELAS. Só isso não basta, devemos definir também o parametro pctincrease como zero também para os TABLESPACES, tudo isso pelo simples fato de que se você definir na tabela e no indice e não no TABLESPACE, os objetos nele hospedados herdaram suas caracteristicas, consequentemente irão gerar fragmentação se este não estiver definido como zero.


Vejamos:

alter table xx storage(pctincrease 0);
alter index xx_id storage(pctincrease 0);
alter tablespace xx_dt default storage(pctincrease 0);

Pronto, definimos nossa tabela, indice e tablespace para 0 (zero).


Mas onde se concentra a problematica das fragmentações? Bom questionamento este, estão exatamente ligados as definições de INITIAL e NEXT, é ai que mora o segredo de se eliminar boa parte de suas fragmentações. É de bom tom também que sempre procuremos fazer uma boa coleta de informações, para que possamos mensurar melhor o quanto será necessário para uma tabela , seja em termos de ,INITIAL ou em termos de ,NEXT, como exemplo posso citar o seguinte. Se você tem uma tabela de 1GB , não ha porque definila com next de 64KB, é obvio que isso vai gerar muito stress, e conseguemtemente fragmentações imensas, e elevadissimas quantidades de extent’s em seu objeto, ao invés de fazermos isso devemos procurar definir um tamanho para o ,NEXT uniforme de acordo com a necessidade e tamanho correto para a tabela, podemos usar como padrão para o ,NEXT neste caso 1MB.
Veja a seguir como proceder :

alter table xx storage(next 1m);
alter index xx_id storage(next 1m);

FRAGMENTAÇÃO POR BLOCO: este tipo de fragmentação é ligado mais aos comandos de exclusão, porque quando linhas são eliminadas de uma tabela , deixam uma lacuna não só nos blocos de dados como nos blocos de indices respectivamente, blocos esses que correspondem ao objeto envolvido na transação. E esse tipo de fragmentação esta ligado aos parametros PCTFREE : e PCTUSED:, os quais podem ser ajustados e alterados para se adequarem as necessidades do sistema. Note que é pura matemática e estatistica nada além disso, associados a raciocinios lógicos e objetivos, afim de proporcionar uma melhor utilização dos seus blocos de banco de dados e com isso assegurar que seu sistema terá uma boa performance sem comprometer o Banco de Dados.


Bem, voltemos ao nosso assunto principal as CHAINED ROWS, ou LINHAS ENCADEADAS para quem preferir.


Podemos detecta-las de maneira simples não é nada do outro mundo, iniciamos o processo de verificação com a utilização da DBMS_STATS utilizando a Procedure GATHER_TABLE_STATS para fazermos uma analise primaria da tabela e coletar as informações que serão usadas no processo em si. Instintivamente podemos pensar que, um número elevado de linhas encadeadas, pode e vai gerar muito stress no seu dia-a-dia, principalmente se seu Banco de Dados for de altos indices de QUERY’s ( consultas), isso pode ser solucionado aumentando o PCTFREE para que haja mais espaço dispobivel no bloco para as leituras e expansão das linhas. Veja como realizar a tarefa :

1.) exec dbms_stats.gather_schema_stats(‘Nome do Esquema’,cascade=>true);
Obs.: aqui coletaremos informações sobre todas as tabelas de um único esquema.

2.) vamos listar as linhas encadeadas após a coleta :

select table_name,
num_rows,
chain_cnt,
avg_row_len,
pct_free,
pct_used
from dba_tables
where chain_cnt > 0
order by chain_cnt desc;

ELIMINANDO AS LINHAS ENCADEADAS


Antes de começar o processo, verifique se em seu Banco existe a tabela CHAINED_ROWS, caso ela não tenha sido criada em outro momento, faça isso agora através do script “ORACLE_HOME/rdbms/admin/UTLCHAIN.SQL”


**Atenção: este processo deve ser preferencialmente executado sem que outras sessões estejam sendo executadas no momento, para que com isso possamos garantir a integridade dos dados, isso é facil de obter colocando o banco em RESTRICT MODE ou simplesmente bloqueando o objeto em questão ( LOCK TABLE ).


Iniciando o processo:
analyze table xx list chained rows into CHAINED_ROWS;
create table temp_xx as select * from xx
where rowid in (select head_rowid from chained_rows
where table_name = 'xx'
and owner= 'OWNER');

Obs.: Neste passo transferimos os dados para uma tabela auxiliar para nos ajudar com o processo de eliminação das linhas encadeadas.

delete from xx
where rowid in (select head_rowid from chained_rows
where table_name = 'xx'
and owner= 'OWNER');

insert into xx select * from temp_xx;


drop table xx_temp;

Bem é isso pessoal, espero que gostem e que consigam realizar sem maiores problemas , atentem para que no Banco versão 9i podemos trabalhar com várias blocagens, o que nos possibilida melhores e maiores flexibilidades. Boa sorte á todos e Sucesso.


Abraço á todos.


David