O Tiro saiu pela culatra e agora???

O que fazer???Olá meu querido amigo, leitor, seguidor, colega de labuta…

Bom dia! Boa tarde! Boa Noite!

He he he “Labuta” foi legal. rsrsrs
Hoje vou falar de um assunto muito importante e que sem dúvida salva empregos…Fiquem atentos!!!

Sabe aquela situação onde as coisas não estão muito performáticas, consultas lentas em uma tabela gigante, a query é boa mas a tabela grande demais, etc, etc, etc?

Semana passada em um projeto onde respondo como DBA responsável de uma equipe, ocorreu que durante algumas execuções um DBA Jr verificou que o uso de um certo índice não estava muito performático, e que embora fosse um índice não era bom. O DBA Verificou que se fizesse full table ainda assim seria melhor que via índice.

Não! O erro dele não foi esse. Não é raro que isso aconteça, ser melhor full do que índice. Sim! Qualquer dia comento sobre isso, mas hoje não foi essa a gafe do nosso amigo. Ele fez a descoberta correta, porém o teste que ele fez para que não utilizasse o índice, foi colocando hint no select forçando o full table.
Nosso herói percebeu que realmente seria melhor sem índice para aquela query. Aqui começa o “detalhe” que só o tempo fará o DBA lembrar e pensar: “Nem sempre uma modificação feita e testada de forma unitária será boa para toda a base”.
Porém, imbuído desta idéia, e tirando conhecimento do fundo da cartola, então ele resolve fazer um teste: Colocar o índice como unusable para que não seja utilizado; uma vez que não poderá colocar hint pois a query vem da aplicação.

Então e ele faz:

alter index tab_grande_idx unusable;

Certo de que está tudo maravilhoso parte para as análises. Porém… O que ele foi perceber só agora é que todas as demais queries que utilizam a mesma tabela também utilizavam o índice, e elas sim precisavam muito dele…
Neste momento então, e só agora, ele se dá conta do que fez…
Essa é a hora que o peão sua frio, vira gago, ou até mudo. rsrsrs

Então, puxa seu conhecimento e parte então para um rebuild para recriar os segmentos do índice o  mais rápido possível, pensando em nem ser notado, e faz:

alter index tab_grande_idx rebuild online;

Hummmmm, nesse momento ele toma o erro:
ORA-14086: a partitioned index may not be rebuilt as a whole

Só então nosso amigo percebe que se tratava de um índice particionado e ele não sabe que terá que fazer por partição.

Bem… Nessa hora o Jr corre para os mais experientes e neste caso fui o escolhido.
Vamos então à solução?

Primeiro você poderá querer descobrir quais partições estarão envolvidas:

SELECT index_name,partition_name
FROM dba_ind_partitions
WHERE index_name=’TAB_GRANDE_IDX’;

Ele irá mostrar as partições envolvida.

Agora segue abaixo um script que irá ajudar a montar o rebuild mais rapidamente, pois não podemos esquecer que temos uma aplicação inteira impactada com isso, portanto, tempo é dinheiro (literalmente).

SELECT ‘ALTER INDEX TAB_GRANDE_IDX REBUILD PARTITION ‘||partition_name|| ‘ online parallel 18 nologging;’
FROM dba_ind_partitions
WHERE index_name=’TAB_GRANDE_IDX’
and status=’UNUSABLE’;

Com o script acima será gerado em tempo real script para rebuild apenas dos índices das partições que estiverem com status de unusable. Bem verdade que no caso do nosso amigo Jr todas estavam como ususable :.(

O resultado dele será algo to tipo:

ALTER INDEX TAB_GRANDE_IDX REBUILD PARTITION PN_ANO_2008 online parallel 18 nologging;

Vale muito lembrar que mesmo colocando parallel, nologging e outras técnicas ninja, com certeza deverá demorar um tempo para conclusão, e este será proporcional ao tamanho do índice.

Apenas para explicar de uma forma simples o que o processo irá fazer, ele irá recriar o índice do zero, fazendo contagens de acordo com o range das partições, recriando e colocando os dados dentro de cada partição.

Dica:
Talvez seja interessante verificar qual a partição mais usada e começar por ela.
Para isso é legal pesquisar a tabela:

SELECT *FROM dba_ind_partitions
WHERE index_name=’TAB_GRANDE_IDX’

Pelo campo HIGH_VALUE conseguirá entender como é feito o range(faixa) de particionamentos e irá entender se poderá fazer algum campo antes.
Este campo representa o “VALUES LESS THAN” da criação da partição.

No caso aqui eu tinha uma tabela de pedidos particionada por mês.

Partição: PN_2016_07
HIGH_VALUE: TO_DATE(‘ 2017-08-01 00:00:00’, ‘SYYYY-MM-DD HH24:MI:SS’, ‘NLS_CALENDAR=GREGORIAN’)

Entendendo: A partição PN_2016_07 traz os valores mais atuais, logo a probabilidade dela ser requerida antes é bem maior. Portanto comecei por ela.

No caso real, causou uma lentidão de aproximadamente 1,5 horas. Como ocorreu no final do expediente, não houve muito impacto, mas poderia ter tido sérias implicações.

Então desta situação tiramos algumas lições:
1- Mesmo que uma configuração, situação pareça ideal para alguma query, pense sempre no sistema como um todo, lembre-se de que as transações em um banco de dados vão bem mais além do que uma query isolada;
2- Sempre analise quais implicações qualquer alteração poderá trazer, por mais que pareça salvação de todos os males;
3- Sempre que possível troque idéia com DBAs mais experientes antes;
4- Se mesmo assim der problema, comunique assim que perceber. Seja profissional e não tente esconder. ACREDITE! A encrenca será bem maior quando descoberta atrasada.

Espero que o post tenha sido bastante útil, que continue acompanhando o blog, comentando, participando e ajudando.

Ah!!! O que aconteceu com o DBA Jr que cometeu a falha??
Nada! Ele aprendeu um pouco mais, e ainda foi homenageado no post de hoje.
Com certeza ele sabe que a história de hoje é  dele e que só terminou bem pelo caráter, profissionalismo de dizer rapidamente: “Raul me ajude que eu errei!”

Sobre raul andrade

DBA e Instrutor Oracle, apaixonado pela minha família e por ensinar.
Esta entrada foi publicada em DBA Oracle. Adicione o link permanente aos seus favoritos.

Deixe uma resposta