terça-feira, 2 de dezembro de 2014

Desabilitando o HINT automático do Top Connect

Desabilitando o HINT do Top Connect com o Oracle


OBS : Faça por conta e risco, teste primeiro ou consulte um Dba.

Para quem trabalha com o Protheus utilizando o Top Connect e o Oracle, já teve por curiosidade ou necessidade, percebido que em todos os selects feitos pela base, sempre tem um HINT adicionado após a palavra SELECT.

Observe uma query gerada pelo Protheus logo abaixo :

SELECT /*+ FIRST_ROWS(50) */
 R_E_C_N_O_
  FROM SA2010
 WHERE R_E_C_N_O_ > 50186
   AND D_E_L_E_T_ = ' '
 ORDER BY R_E_C_N_O_

Observe na query acima que existe uma linha /*+ FIRST_ROWS(50) */ que pode variar um pouco mas o significado é o mesmo.

Este trecho na query faz com que o banco ignore o plano de execução que o Oracle iria executar e de forma forçada, executa a instrução que o Protheus impôs.

De certa forma não de todo ruim, porque, se a base de dados não estiver bem configurada, o Protheus poderia ficar com uma performance bem até pior.

Particularmente, o FIRST_ROWS(50) significa que o Oracle deve retornar os primeiros 50 registros retornados de um Select de forma imediata e posteriormente, o restante o banco poderia carregar com menos prioridade.

Não esta errado, mas vale lembrar que estamos dizendo que o plano de execução gerado pelo Protheus, é melhor do que o plano que seria gerado pelo Oracle.

Se o Top Connect não executasse esta instrução, o plano de execução resultado da query poderia ser o mesmo para ambos os casos e iria depender de como esta configurado o parâmetro OPTIMIZER_MODE.

Atualmente o Top Connect não permite que o Hint seja desabilitado, mas podemos fazer o desligamento desse parâmetro diretamente pelo banco de dados.

Como havia dito anteriormente, este procedimento deve ser executado por um Dba. Este parâmetro desabilita o uso do Hint inclusive para o próprio funcionamento do Oracle.

Então, mão na massa.

Para desabilitar o HINT no banco de dados, temos que executar o seguinte comando no Oracle :

SQL> ALTER SYSTEM SET "_optimizer_ignore_hints"= TRUE SCOPE=BOTH;

Obs: Para surtir efeito, é necessário que a sessão do usuário não seja a mesma.

Este comando não ira alterar o resultado da query, somente ira deixar o plano de execução ser gerado pelo Oracle ao invés de ser imposto pelo Protheus.

Veja como ficou o resultado da mesma query :

SELECT /*+  */
 R_E_C_N_O_
  FROM SA2010
 WHERE R_E_C_N_O_ > 50186
   AND D_E_L_E_T_ = ' '
 ORDER BY R_E_C_N_O_

Observe que a query e o resultado dela sera o mesmo, a diferença é o plano de execução.

Para quem não sabe o que é um plano de execução, vou resumir de forma simplificada.

Quando executamos uma query, o banco antes de qualquer coisa faz um PARSE, ou seja, primeiro ele verifica se a query esta escrita corretamente, se o usuário tem permissão, se a tabela existe, verifica se a instrução já estava na memória, etc, não vou entrar no assunto DBA, vou deixar para outro dia.

Feito isso, o Oracle vai decidir como ele ira retornar esses dados, de uma forma bem grotesca imagine ima viagem para o interior. Existem diversos caminhos e rodovias que podemos pegar mas dependendo do trânsito podemos pegar o caminho mais longo para chegarmos mais rápido.

Essa inteligência o Oracle tem e já faz sozinho se a sua base estiver bem configurada e com as estatísticas atualizadas.

Com o parâmetro dos HINTS desligados ao invés do Protheus impor um caminho, fica a cargo do Oracle fazer e montar o melhor trajeto.

Desligar ou não o HINT é uma decisão de cada administrador, por isso faça a conta do ganho de tempo ao desligar este parâmetro.

Abraços a todos.

O que não fazer ao utilizar o dbUseArea

O que não fazer ao montar uma query

É muito comum por falta de experiência, por pressa ou falta de conhecimento, independentemente da linguagem esquecermos de fazer uma análise melhor dos dados que puxamos em nosso banco de dados.

Certo dia estava naquela correria para montar um Web Service para cancelamento de notas fiscais e sai fazendo daquele jeito.

Depois fui fazer uma manutenção no programa e encontrei a seguinte linha :

//PREENCHENDO OS ITENS DA NOTA FISCAL (SD1) 
cQuery := " SELECT * FROM " + RetSqlName("SD1") // * FROM é coisa porca. Depois vou arrumar
cQuery += "    WHERE D1_FORNECE = '"+ cfornecedor + "'" 
cQuery += "    AND D1_LOJA = '"     + cLoja       + "'" 
cQuery += "    AND D1_DOC = '"      + cNota       + "'" 
cQuery += "    AND D1_SERIE = '"    + cSerie      + "'"                    
cQuery += "    AND D_E_L_E_T_ = ' '" 


Na linha destacada acima, veja que utilizei o SELECT * FROM ao invés de mencionar o nome dos campos como D1_FORNECE, D1_LOJA, D1_DOC, D1_SERIE, etc....

Parece preciosismo mas não é, um usuário rodando este programa a perca é imperceptível mas quando rodamos em um ambiente com muitos usuários teremos uma boa perca de performance.