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.

quarta-feira, 26 de novembro de 2014

Webservice no Protheus - Parte 3 - Final

Notas do WebService

Algumas pessoas questionaram porque em alguns casos o Webservice não esta ativo ou porque retorna mensagens de erro.

No exemplo, quando o WebService não esta HABILITADO procure verificar se existe algum erro na compilação do programa.
Mesmo compilado com sucesso não quer dizer que a rotina esta correta. Como sabemos, o Protheus não é fortemente tipado, ou seja, qualquer coisa ele deixa passar.

Se no meio do código escrever PARALELEPÍPEDO e compilar, esta compilação sera feita com sucesso.

Outra coisa, caso retorno Nulo e ocorra um erro, é devido eu não ter tido tempo de fazer a tratativa das exceções, ando meio corrido e sem tempo para fazer publicações.

Uma correção :

Em NameSpace onde o nome esta ServiceReference1, troquei para ClientWSProtheus.

Vale lembrar que o WebService MeuPrimeiroWebService é possível adicionar diversos métodos.
Sempre que fizer alguma alteração em métodos, na aplicação do Visual Studio ou Java, é necessário atualizar a referência.

Como premissa, você deve conhecer alguma coisa de ADVPL e do Visual Studio.

Se você gostou do artigo, clique nos links patrocinados.

Saudações.

segunda-feira, 15 de setembro de 2014

Webservice no Protheus - Parte 2 - Montando uma aplicação básica

A partir deste post, você vera como testar uma aplicação básica

Montagem da classe do Webservice

Este Webservice terá a finalidade retornar os dados do cliente no Protheus, a aplicação .NET ira enviar uma solicitação que poderia ser no formato de um XML ou por passagem simples por parâmetros.
Para não complicar muito, o primeiro exemplo de passagem de parâmetros é mais indicado.

O resultado final é o retorno do Nome do cliente, endereço, bairro, cidade, uf e CEP.
A passagem de parâmetros será o código do cliente e a loja.

No exemplo abaixo, não fiz nenhum tipo de validação e não estou preocupado com isso neste momento, fica a cargo de meus leitores corrigir o programa.
Em meus projetos consulto usuários, bloqueio senhas, envio estruturas complexas de XML, etc.

Então, mão na massa.

Primeiro, crie um arquivo no seu projeto, no meu caso criei com o nome MeuPrimeiroWebService.PRW

#INCLUDE 'PROTHEUS.CH'
#INCLUDE "XMLXFUN.CH"
#INCLUDE "APWEBSRV.CH"
#include "topconn.ch"
#INCLUDE "RWMAKE.CH"
#INCLUDE "TBICONN.CH"
#INCLUDE "ERROR.CH"

// Estrutura de dados. Montagem do Array de retorno
// Não necessariamente retorna-se em um Array, pode ser possível retornar em uma string simples,
// neste caso não utilizaria uma Estrutura
WSSTRUCT AWSRTDados
    WSDATA ClienteNome     AS String
    WSDATA ClienteEndereco AS String
    WSDATA ClienteBairro   AS String
    WSDATA ClienteCidade   AS String
    WSDATA ClienteUF           AS String
    WSDATA ClienteCEP          As String
ENDWSSTRUCT 

// WebService
WSSERVICE MeuPrimeiroWebService DESCRIPTION "Descrição do meu primeiro WebService"
       // Passagem dos parâmetros de entrada
       WSDATA ClienteCodigo  AS string
       WSDATA ClienteLoja    AS string
      
       // Retorno de um array que deve retornar a COLUNA 1, COLUNA 2
       WSDATA aRetornoCliente AS ARRAY OF AWSRTDados

       // Descrição dos métodos que o WEBSERVICE pode possuir
       /*WSMETHOD ExcluiOrdem     DESCRIPTION "Efetua a exclusão de uma ordem de faturamento"
       WSMETHOD DeletaNfSaida   DESCRIPTION "Consulta ou exclui uma nota fiscal de vendas"
       WSMETHOD DeletaNfEntrada DESCRIPTION "Consulta ou exclui uma nota fiscal de compras"
       WSMETHOD AtualizaProduto DESCRIPTION "Inclui / Altera um produto no Microsiga SB1"
       WSMETHOD MeuXML          DESCRIPTION "Meu XML"
       WSMETHOD SenhaProtheus   DESCRIPTION "Teste se a senha esta Ok"*/
      
       WSMETHOD ConsultarCliente DESCRIPTION "Retorna os dados do cliente"
      
ENDWSSERVICE

/************************************************************************************
** Consulta os dados do cliente
** Abaixo, separei o que se refere do webservice da aplicação que realmente ira
** processar os dados. Lembrando que não é obrigatório
************************************************************************************/
WSMETHOD ConsultarCliente WSRECEIVE ClienteCodigo, ClienteLoja WSSEND aRetornoCliente WSSERVICE MeuPrimeiroWebService
Local aRetFuncao := {}

    aRetFuncao     := u_xxRtCliente(::ClienteCodigo,::ClienteLoja) // Passagem de parâmetros para rotina
  
    aAdd(::aRetornoCliente, WSClassNew("AWSRTDados") )
    ::aRetornoCliente[01]:ClienteNome    := aRetFuncao[1][1]
    ::aRetornoCliente[01]:ClienteEndereco:= aRetFuncao[2][1]
    ::aRetornoCliente[01]:ClienteBairro  := aRetFuncao[3][1]
    ::aRetornoCliente[01]:ClienteCidade  := aRetFuncao[4][1]
    ::aRetornoCliente[01]:ClienteUF      := aRetFuncao[5][1]
    ::aRetornoCliente[01]:ClienteCEP     := aRetFuncao[6][1]

Return .T.

/*************************************************************
** Retorna os dados do cliente
**************************************************************/
User Function xxRtCliente(pClienteCodigo, pClienteLoja)
Local aRetornoDados         := {}
Local aTables    := { "SA1","SM0" }

Conout(dtoc( Date() )+" "+Time()+ " == Abrindo ambiente TOP CONNECT =======")
RPCSetType( 3 )
RpcSetEnv ( "01", "01", Nil, Nil, "FAT", Nil, aTables )

SA1->(DbSetOrder(1))
SA1->(DbGoTop())

If SA1->(DbSeek(xFilial("SA1") + pClienteCodigo+ pClienteLoja))
         aAdd(aRetornoDados ,{SA1->A1_NOME                       })  // 1
         aAdd(aRetornoDados ,{SA1->A1_END                       })  // 2
         aAdd(aRetornoDados ,{SA1->A1_BAIRRO                     })  // 3
         aAdd(aRetornoDados ,{SA1->A1_MUN                        })       // 4
         aAdd(aRetornoDados ,{SA1->A1_EST                        })       // 5
         aAdd(aRetornoDados ,{SA1->A1_CEP                        })  // 6
Else
         aAdd(aRetornoDados ,{Nil})  // 1
         aAdd(aRetornoDados ,{Nil})  // 2
         aAdd(aRetornoDados ,{Nil})  // 3
         aAdd(aRetornoDados ,{Nil})  // 4
         aAdd(aRetornoDados ,{Nil})  // 5
         aAdd(aRetornoDados ,{Nil})  // 6     
Endif

Return aRetornoDados

Feito isto, vamos verificar se não existe nenhum erro na compilação pesquisando pelo o endereço ja configurado. A configuração expliquei na Parte 1

http://192.168.15.86:889/ws/WSINDEX.apw 



Ao clicar no link, aparece a configuração que deve ser utizada no Visual Studio ou qualquer outra aplicação


Vamos agora no Visual Studio...

Em adicionar referência, colar o link MEUPRIMEIROWEBSERVICE.apw?WSDL conforme figura abaixo :


No visual Studio vamos montar uma telinha


Agora, vamos montar um código simples, quero deixar claro que não sou especialista em c#, sou um mero fuçador.

private void button1_Click(object sender, EventArgs e)
        {
            // Instanciamos a nossa referência com o WebService do Protheus
            ClientWSProtheus.MEUPRIMEIROWEBSERVICESOAPClient aleksandro = new ClientWSProtheus.MEUPRIMEIROWEBSERVICESOAPClient();

            // Montamos uma ILIST, poderia ser uma string qualquer, existem diversas formas de fazer
            IList<AWSRTDADOS> aRetorno;

            // Chamo o método e retorno em um array
            aRetorno = aleksandro.CONSULTARCLIENTE(ParamCodigo.Text, ParamLoja.Text);

            // Jogo nos campos os dados da empresa
            textBox3.Text = aRetorno[0].CLIENTENOME.ToString();
            textBox4.Text = aRetorno[0].CLIENTEENDERECO.ToString();
            textBox5.Text = aRetorno[0].CLIENTEBAIRRO.ToString();
            textBox6.Text = aRetorno[0].CLIENTECIDADE.ToString();
            textBox7.Text = aRetorno[0].CLIENTECEP.ToString();
            textBox8.Text = aRetorno[0].CLIENTEUF.ToString();

        }

Executando o programa, vejamos o que o Protheus ira retornar


Pronto, a consulta foi feita unicamente pelo WEBSERVICE sem se conectar diretamente na base de dados.

Da mesma forma que podemos fazer uma consulta, também é possível fazer um programa EXECAUTO, ou rodar rotinas padrão do Protheus.

Esta foi uma forma de fazer, mas existem diversas maneiras. Queria somente ilustrar uma delas.



Webservice no Protheus - Parte 1 - Configurando o Protheus

Configurando o WebService no Protheus

Antes de iniciarmos o estudo do WebService, é imprescindível a configuração do serviço do Protheus.

Para isto devemos ter um serviço separado dos outros. A separação é recomendada mas não é obrigatória.

Não estou explicando de forma detalhada cada linha da configuração abaixo, devido a documentação estar disponível no portal TDN da Totvs. Estou focando no uso geral da aplicação WebService.

Abaixo, segue um modelo do WebService que utilizo


[WEBSERVICE]
SourcePath=E:\PROTHEUS11\APO\WEBSERVICE
RootPath=E:\PROTHEUS11\Protheus_Data
StartPath=\system\
x2_path=
RpoDb=Top
RpoLanguage=portuguese
RpoVersion=110
LocalFiles=ads
Trace=0
localdbextension=.dbf
PictFormat=AMERICAN
DateFormat=DEFAULT
RegionalLanguage=BRA

Note que no trecho acima, não tem nada de diferente do que utilizamos normalmente.

[192.168.14.33:82/ws]
ENABLE=1
PATH=e:\Protheus11\Protheus_Data\web\ws
ENVIRONMENT=WEBSERVICE
INSTANCENAME=Ws
RESPONSEJOB=JOB_WS_9901
DEFAULTPAGE=wsindex.apw

No trecho acima, estamos configurando o endereço, nome do ambiente, nome dos jobs e página de índice com os nomes dos serviços disponíveis do nosso WebService.

[JOB_WS_9901]
TYPE=WEBEX
ENVIRONMENT=WEBSERVICE
INSTANCES=1,80
SIGAWEB=WS
INSTANCENAME=Ws
ONSTART=__WSSTART
ONCONNECT=__WSCONNECT

No trecho acima, mencionamos o nome do Job, ambiente, quantidade de instâncias simultâneas.

[TopConnect]
DataBase=ORACLE
Server=NOMESERVIDOR
ALIAS=PROTHEUS
PROTHEUSONLY=0

[Drivers]
Active=TCP

[TCP]
TYPE=TCPIP
Port=1255

[General]
InstallPath=E:\PROTHEUS11

[LICENSECLIENT]
SERVER=SERVIDORLICENCA
port=5555

[HTTP]
enable=1
port=82
PATH=e:\PROTHEUS11\PROTHEUS_DATA\web\ws
ENVIRONMENT=WEBSERVICE

[MAIL]
Protocol=POP3

Montando a aplicação


quinta-feira, 17 de abril de 2014

Webservice no Protheus de verdade

Criando um Webservice no Protheus e utilizando no C# ou no PLSQL.


Boa noite, faz um tempo que não posto nada, ando meio ocupado por isso parei de postar. Nem sei se alguém acessa este blog, mesmo assim pra quem der azar de cair aqui, vou postar um exemplo completo e muito bem detalhado de como montar um WebService no Protheus desde a configuração até a publicação e consumo pelo o Protheus ou pelo C#.

Como é um artigo muito longo, vou postando durante a semana e farei por partes.

Na primeira parte, vou postar como montar o serviço do WebService e sua configuração.

Em que situação devo utilizar o WebService

Para quem é novo e não conhece, o WebService tem uma enorme utilidade para integração, compartilhamento de informações, troca de dados, etc.

Não vou detalhar o que é já que no google existem diversos artigos, páginas que explicam com muito mais detalhe o que é, mas de forma muito resumida, é uma forma de troca de dados e acesso á métodos entre sistemas diferentes.

Exemplificando... como se beneficiar do WebService no Protheus .

Cenário 1

Tenho uma empresa que compra e distribui produtos de um segmento qualquer. Esta possui um portal onde expõe seus produtos.
Outras empresas de varejo também possuem portais onde vendem desta vez para o consumidor final.
A empresa de varejo não mantem estoque e nem o prazo de entrega da mercadoria.
Para que o consumidor final deste portal saiba do estoque e prazo de entrega, seria necessário acessar a base de dados do fornecedor de origem para consultar estes dados.
Então entra o WebService. O site da empresa varejista, acessa o banco de dados da empresa fornecedora através de acesso aos métodos que estão armazenados no WebService.
A programação deste serviço não importa. Pode ser feita em Delphi, C#, ADVPL, PLSQL, etc... O importante é a troca de dados que é feita através do protocolo SOAP que é padrão para todos estes sistemas.
A possibilidade de consultar ou executar um comando no banco de dados entre a empresa A e a empresa B viabiliza o uso.

Cenário 2

Possuo o ERP Protheus em minha empresa. Para envio das notas fiscais eletrônicas, é necessário consumir o WebService do Governo. O Governo por sua vez, não permite e não confia que as empresas possam jogar, consultar e manipular as informações deste cadastro.
Desta forma o Governo disponibiliza um WebService, onde o Protheus acessa de forma INDIRETA e CONTROLADA o banco de dados e os métodos armazenados neste WebService.
De uma forma mais tosca de explicar, é poder trocar informações entre múltiplos sistemas sem que eu acesse de forma direta o banco de dados ou aplicação.

Cenário 3

Uma empresa possui um sistema legado e precisa acessar funções padrão do Protheus ou outro ERP qualquer. O sistema legado não sabe como chegar em uma determinada informação, mas sabe que determinada função dentro do Protheus faz isso.
O sistema legado não tem como acessar o Protheus e chamar determinada função.
Como solução, é criado um WebService no Protheus que disponibiliza esta função. Esta função pode ser acessada pelo sistema legado, pelo próprio Protheus ou qualquer outro que utilize o protocolo SOAP.

Resumindo, esta troca de dados pode ser utilizada em SmartPhones, portais, aplicações Desktop, etc.

Para os que tem alguma duvida de como funciona e até mesmo o que é, no do Wikipedia explica de forma bem intuitiva o seu funcionamento.


No próximo artigo, explico como configurar e montar um serviço de Webservice do Protheus.

Configurando o Webservice no Protheus

quinta-feira, 13 de fevereiro de 2014

Uso excessivo de distinct em banco de dados

Pra que usar distinct 

O comando distinct serve para eliminar linhas duplicadas em uma select. É um comando muito útil quando queremos remover linhas duplicadas quando todas as colunas resultam a mesma coisa.

O resultado final sera uma select com os dados já filtrados.

Eu particularmente não gosto, não recomendo e acho que o distinct é um comando utilizado para programadores preguiçosos. Nossa, não me matar por isso.

Veja, essa é minha opinião.

Em um sistema de padaria feito em casa com poucos registros é até válido. Mas vamos pensar em um ambiente compartilhado com um grande volume de informações e leituras em massa. O fato do banco retornar sua consulta em alguns segundos não quer dizer que esta consulta esta otimizada.

Dentro do banco de dados, muita coisa acontece somente para trazer esses registros filtrados.

Os problemas de performance ficam piores quando a base começa a crescer. Mas não deixe para otimizar suas querys somente após o problema começar, comece desde o primeiro registro pensando como essa informação sera resgatada posteriormente.

Mais da metade de problemas de lentidão no banco é devido as instruções SQL mal escritas.
O restante são ajustes, infra, sistema operacional e configurações diversas.

Como o banco de dados trata o distinct

Ao montar uma consulta, o banco de dados primeiramente procura um plano de execução que ja foi montado previamente.
Quando ele não encontra, ele ira fazer um hard parse. Isto é, ele vai verificar diversas coisas antes de retornar sua consulta. Exemplo : O usuário logado tem acesso ao banco, essa tabela existe, a select esta certa, quais são as colunas dessa tabela, as instruções estão na memória do servidor, os dados estão na memória, como vou buscar esses dados ?.
Feito isso, o banco ira retornar os dados.
Olha o tempo que perdemos com isso ?. 1 segundo... Agora imagine 1000 pessoas consultando ao mesmo tempo ?.

O distinct é mais um complicador.

Mas vamos dar um exemplo.

Tenho uma consulta que ira me trazer 5 milhões de registros, mas, eu preciso somente de 100 registros porque o resto é duplicação.

Ai vai lá o desenvolvedor e tem a brilhante ideia...DISTINCT nele.

O banco vai levar na memória 5 milhões de registros e utilizando CPU de forma desnecessária ele ira exibir somente os 100 registros que interessa.

Derrepentemente a base cresce de 5 milhões para 100 milhões de registros. Ai começa... o banco tá lento... o banco tá um lixo. Não... o banco não tá um lixo... A sua query é que é um lixo.

Ai chega o DBA e descobre o problema cobrando uma fortuna.

Quando for fazer uma query e precise filtrar registros duplicados, tenho duas técnicas que pode ser substituída pelo o Discinct 

1) Utilize GROUP BY

2) Faça todas as amarrações entre as tabelas utilizando preferencialmente os índices entre elas

Entenda primeiramente as tabelas, suas amarrações e principalmente, estude normalização de banco de dados.

Em breve irei postar um artigo sobre normalização de banco de dados.


terça-feira, 4 de fevereiro de 2014

Configurando o Top Connect para o Oracle

Configurando o Top Connect para o Oracle

O Protheus como muitos sabem, pode trabalhar com diversos bancos.
Sua configuração para o Top Connect é um pouco complicada e requer experiência. Mas com o procedimento abaixo, qualquer um conseguira fazer.

Vamos lá então.

Configurando o Oracle

Antes de qualquer coisa, é necessário configurar o Net Manager. 
Neste caso, já estou imaginando que o Top Connect foi instalado em um servidor / estação onde já existe o client do Oracle instalado.


Faça o teste 



Instalando o Top Connect

A primeira coisa que devemos identificar, é se o sistema operacional é 32 ou 64 bits.
Neste exemplo, a configuração é para Windows 64 bits, e em breve irei postar como fazer a mesma instalação pelo Linux.
Note que o banco pode estar em Linux ou Windows, a configuração que estou me referindo, é para o local em que o Top Connect sera instalado.

Após baixar e instalar o top connect, acessar o monitor do Top e digitar o nome do servidor em que o programa foi instalado


Configurar o Top Connect. Alterar conforme as configurações do seu banco de dados.



Salve

Agora, vá até o local do executável do Top Connect, e faça algumas alterações no arquivo INI 

[General]

Port=7890
LicenseServer=SERVER01
LicensePort=5555 ;Local da instalação do Hard Lock
ByYouProc=0

Adicionar as linhas em vermelho

[ORACLE] ;Nome daquele ambiente que disse que iria dizer depois pra que servia
OCIVersion=8 ; Manter se for Oracle acima da versão 8
ORACLE_HOME=C:\ORACLE\sistema\product\11.2.0\dbhome_1 ; Local da instalação do aplicativo do Client do Oracle

Feito isso, vamos testar



Feito isso, agora é necessário configurar o serviço do Protheus.
A configuração relacionada ao Top Connect para o Oracle termina aqui.

segunda-feira, 3 de fevereiro de 2014

ADVPL-Dicas de uso racional do banco de dados com o Protheus

Utilizando o banco de forma racional

Muitas vezes contratamos um DBA, uma consultoria mas notamos que a performance do Protheus não é boa. Mas porque isso acontece, como resolver esse problema ?.

Primeiramente, é necessário deixar claro que não existe uma formula magica, onde ao apertar um simples botão, todos os seus problemas serão solucionados.

Se existe uma fórmula magina, na minha opinião é entender o problema. Entender o que esta acontecendo com o Protheus e minha base de dados. Geralmente não é um único problema mas um conjunto de problemas que deixam a base / Protheus cada vez mais lento.

Identificando o problema

Geralmente se a base estava normal e derre pente o banco ficou extremamente lento, é importante pensar em algumas possibilidades :
  • Foi feita alguma atualização do ERP ou banco de dados ?
  • Foi feito alguma atualização do sistema operacional ?
  • O servidor possui espaço livre em disco ?
  • Alguma coisa foi feita no banco de dados ?
Provavelmente, se você respondeu sim para qualquer uma das alternativas acima, isso significa que a atualização não foi bem planejada. É por este motivo que é necessário contratar um profissional especializado.

Melhorando as consultas de querys

Com o Protheus, não é possível utilizar planamente todos os recursos do banco de dados, mas é possível chegar bem próximo do usável.

Utilize corretamente os índices da tabela

Abaixo, vou extrair as informações de um cadastro de clientes da maneira mais chula que existe. Veja o quanto custa para o banco de dados

SELECT * FROM SA1010 SA1010
WHERE SA1010.A1_COD = '009144'

Figura 1

Veja o custo para a CPU para o banco de dados. Agora vamos melhorar a consulta para minha necessidade mas utilizando corretamente os índices do Protheus.

SELECT SA1010.A1_COD, SA1010.A1_NOME
  FROM SA1010 SA1010
 WHERE SA1010.A1_COD = '009144'
   AND SA1010.A1_LOJA = '01'
   AND SA1010.A1_FILIAL = '  '
   AND SA1010.D_E_L_E_T_ = ' '

Figura 2

Observe na figura acima e comparando com a primeira figura, que o resultado sera o mesmo mas o custo para o banco de dados foi muito menor.

Mas porque isso aconteceu ?.

Isso aconteceu porque utilizamos corretamente todos os índices para aquela tabela.
Note também que ao invés de mandar exibir todas as colunas, listei somente as colunas que realmente havia a necessidade de trazer.
Sempre que for construir uma nova consulta, é importantíssimo verificar os índices que o Protheus criou.

Geralmente ao utilizar uma busca por DBSEEK, ja estamos utilizando o recurso dos índices devido ao comando DBSETORDER.
O DBSETORDER ao receber qual é o número do índice, faz o Protheus montar a query utilizando dos índices cadastrados na tabela SIX.

Crie índices para melhorar a performance mas cuidado para não exagerar.


Um índice no banco de dados, é uma tabela com as colunas indexadas com o endereço físico da informação que deseja pesquisar.
Se você sair criando índices para todas as colunas, este índice passa a ser uma tabela. Índice aumenta o tamanho de seu banco de dados, deixa mais lento a gravação. No exemplo da figura 2 note que o A1_FILIAL esta com dois espaços em branco. Isto ocorre porque minha tabela SA1 é uma tabela compartilhada. Como o A1_FILIAL faz parte do índice eu utilizei dois espaços em branco para o Oracle não ter que varrer o índice.

Se conseguir, desapareça com os filtros personalizados

Usuário é um artista. Quando você pensa que ele já fez de tudo, sempre aparece uma coisa nova.

Conforme havia falado do comando DBSETORDER, ao definir o número do índice, o Protheus vai montar a query utilizando todas as colunas que foram indexadas.
O Problema do FILTRO PERSONALIZADO, é que ele pode não utilizar o índice do banco.
Mas... porque ?

Porque o usuário vai montando o índice do jeito que ele quer.
Exemplo :

O usuário recebe um depósito no banco tal. Mas ele não sabe quem depositou porque era para ter sido pago por um boleto bancário.
Então ele faz oque !. Ele monta um filtro personalizado e digita o valor do título. Valor não esta indexado, então o banco faz oque ?. Sai varrendo todo o banco de dados até encontrar o valor.
Toda essa tabela vai ficar na memória do banco do servidor, esvaziando tudo o que estava em cache para carregar a consulta do tal usuário.
Esta operação, deixa por algum tempo o banco de dados lento.

Para quem não sabe qual é o filtro personalizado, é aqui :

Figura 3
Este tipo de filtro eu chamo de destruidor de banco de dados.

Tente entender porque o usuário precisa disto. Onde isso vai ser útil no dia a dia.

Muitas vezes a lentidão da contabilidade, foi causada por um filtro incorreto lá do módulo financeiro.

Padronize o suas querys


O banco de dados monta um plano de execução para retornar a informação desejada.
Para o banco de dados, um SELECT * FROM é diferente de um select * from.
O banco de dados ira montar um hard parser, isso quer dizer, que o banco ira verificar novamente toda a query como : O usuário tem acesso nesta tabela ?. Esta tabela existe ?. As colunas estão corretas ?. A tabela esta na memória do servidor ?. Não... então vou carregar.
Se tiver mais de um analista, converse com ele para esta padronização.

Rode as estatísticas


Quando uma atualização do banco de dados é feita, o Protheus geralmente adiciona novos índices. Ao criar estes índices, o banco automaticamente já faz a estatísticas para aquele índice mas isso não quer dizer que outras coisas precisam ser corrigidas.
Procure um DBA que ele pode fazer uma análise melhor do que esta ocorrendo.

Para resumir, existem muitas coisas que podem e devem ser feitas no banco de dados e eu poderia ficar escrevendo muitas páginas sobre este assunto.

A melhor forma de melhorar a performance do Protheus, é Procure um Dba qualificado no banco de dados que esta instado na sua empresa, e que principalmente Entenda o Protheus.


Não de voltas atoa. Cuidado com a cardinalidade


(Pra que retornar um milhão de linhas se somente uma única linha sera aproveitada)

Já vi cada coisa maluca por ai. Fui em uma empresa que o analista criou um relatório que fazia o seguinte :

A query fazia um select no banco de dados inteiro e depois no final, existia um ROWNUM =1. Ai fiquei pensando, pra que isso ?. Quando questionei o analista, ele me disse que era porque ele precisava somente de um único registro, ou seja o primeiro que vier.
Para o analista que montou, parece um preciosismo achar que o ROWNUM vai deixar o banco lento. Não é o ROWNUM que vai deixar lento, é a volta.

Não fique no acho que ta bom, tenha uma métrica, não quer dizer que porque a consulta retornou um certo dado em 1 segundo que a consulta esta boa.

Cuidado com o Distinct


Na minha opinião, distinct é coisa de quem não sabe o que esta fazendo ou de analista preguiçoso.
Muitas vezes é melhor fazer diversas consultas pequenas do que uma consulta muito complexa. Se você sabe o que esta procurando, não tem a necessidade de utilizar o distinct.