DNATech :: Otimizando customizações Protheus: quando parar de processar linha a linha muda tudo

# Otimizando customizações Protheus: quando parar de processar linha a linha muda tudo

Um dos maiores desafios em customizações Protheus não está apenas na regra de negócio. Muitas vezes, o gargalo real está na forma como a rotina acessa, filtra e grava os dados.

Recentemente trabalhei em uma otimização envolvendo rotinas ligadas à apuração e expectativa de comissão. O resultado foi uma mudança expressiva de desempenho: o processo, que antes dependia de buscas e inclusões linha a linha, passou a executar a maior parte da carga diretamente no banco, com `INSERT INTO ... SELECT`.

## O problema

A rotina original fazia muito processamento procedural:

- percorria vendedores um a um;
- fazia validações repetidas em `SA3` e em tabela customizada de regras;
- utilizava o padrão conhecido como RBAR, *Row By Agonizing Row*, dentro de loops;
- populava tabelas temporárias item a item;
- em alguns cenários, processava mais empresas e filiais do que o necessário.

Esse padrão é comum em customizações antigas: funciona, respeita a regra, mas escala mal. Quando o volume de vendedores, notas, itens ou filiais cresce, cada busca individual vira custo acumulado.

## A estratégia adotada

A primeira decisão foi centralizar a regra de obtenção e montagem dos dados em um único ponto.

Em vez de manter regras parecidas espalhadas entre vários programas, o fluxo foi reorganizado para que exista uma rotina principal responsável pelo cálculo, pela montagem das tabelas temporárias e pela consolidação das informações.

Com isso:

- o documento corrente é identificado no ponto de origem;
- os parâmetros necessários são repassados para a rotina central;
- a rotina central decide se deve processar um relatório completo ou apenas um documento específico;
- a montagem da comissão e dos detalhes passa a ser feita por SQL direto.

Para pedidos, a origem dos dados pode ser composta por tabelas como `SC5/SC6`.

Para orçamentos, a origem pode ser composta por tabelas como `SCJ/SCK`.

A regra de negócio permanece centralizada, mas a origem dos dados muda conforme o contexto.

## Substituindo loop por consulta em lote

Um dos maiores gargalos era a seleção de vendedores usando busca individual na tabela customizada de regras.

O padrão anterior era conceitualmente assim:

```advpl
While SA3->(!Eof())
    If REGRA->(BuscaRegra(...))
        aAdd(aVendedores,...)
    Endif
    SA3->(dbSkip())
EndDo
```

A melhoria foi trocar isso por uma carga em lote, usando SQL para juntar `SA3` e a tabela de regras de uma vez.

Isso reduz drasticamente:

- quantidade de round trips;
- troca de contexto entre AdvPL/TLPP e banco;
- uso de alias em loop;
- custo acumulado de busca por vendedor.

A regra permanece a mesma, mas o banco passa a fazer o que ele faz melhor: filtrar, juntar e retornar conjuntos.

## Carga direta nas temporárias

Outro ponto importante foi a criação das tabelas temporárias de comissão e detalhes.

As tabelas continuam sendo criadas com os recursos tradicionais do Protheus, como `CriaTrab()` e `dbCreate()`, mas a alimentação deixou de ser feita com `RecLock()` ou `dbAppend()` linha a linha.

A nova abordagem usa:

```sql
INSERT INTO tabela_temporaria (...)
SELECT ...
FROM ...
JOIN ...
WHERE ...
```

Isso foi aplicado tanto na tabela de resumo quanto na tabela analítica.

A vantagem é direta: em vez de o AppServer controlar milhares de pequenas inserções, o banco executa uma operação set-based, muito mais eficiente para grandes volumes.

## Atenção ao R_E_C_N_O_

Um detalhe importante em Protheus: nem toda tabela temporária criada dessa forma terá `R_E_C_N_O_` autoincremental no banco.

Durante os testes, isso ficou evidente com violação de chave primária, pois os registros estavam sendo inseridos com `R_E_C_N_O_ = 0`.

A solução foi gerar o recno diretamente no `SELECT`, usando uma composição baseada em:

```sql
MAX(R_E_C_N_O_) + ROW_NUMBER()
```

Assim, cada carga direta já grava a temporária com chave válida, sem depender de autoincremento inexistente.

Esse ponto é essencial em otimizações Protheus com tabela física temporária: não basta fazer `INSERT INTO ... SELECT`; é preciso respeitar a estrutura que o DBAccess espera.

## Empresa e filial: cuidado obrigatório

Outro ponto importante é que tabelas Protheus são físicas por grupo de empresas.

Por isso, o processamento normal de um relatório continua respeitando empresa e filial em iterações separadas.

No entanto, quando a chamada vem de um documento já posicionado, como um pedido ou orçamento, o contexto é diferente. O usuário não está solicitando uma apuração ampla; ele quer a expectativa daquele documento específico.

Nesse caso, não faz sentido:

- abrir perguntas;
- iniciar processamento em job;
- percorrer todas as empresas e filiais;
- recalcular um universo maior que o documento corrente.

A solução foi criar um modo de processamento por documento.

Quando a rotina recebe o tipo do documento e o `RecNo()`, ela processa apenas a empresa e filial correntes, chamando a função de cálculo diretamente.

Sem job, sem varredura geral e sem interface de parâmetros.

## Resultado técnico

A otimização trouxe ganhos em três frentes:

1. **Performance**

   O processamento pesado foi empurrado para o banco, reduzindo loops, buscas repetidas e inclusões linha a linha.

2. **Manutenção**

   A regra principal ficou concentrada em um único ponto, evitando duplicação entre relatório, consulta e expectativa de comissão.

3. **Segurança funcional**

   O fluxo normal do relatório continua respeitando o processamento por empresa e filial. Já o fluxo vindo de um pedido ou orçamento usa somente o documento corrente.

## Lições aprendidas

Nem toda otimização em Protheus é sobre trocar índice, criar tabelas novas ou ajustar uma query isolada.

Às vezes, o maior ganho vem de mudar o desenho da rotina:

- sair do pensamento registro a registro;
- usar SQL para operações em lote;
- preservar o contexto empresa/filial;
- centralizar regra de negócio;
- tratar corretamente `R_E_C_N_O_`;
- separar claramente relatório, consulta e expectativa de documento.

Customização boa não é apenas a que funciona. É a que funciona bem com volume, respeita a arquitetura do Protheus e continua fácil de manter depois.

---

#DNATech #Protheus #TOTVS #AdvPL #TLPP #SQLServer #Performance #ERP #Customizacao #DBAccess

Comentários

Postagens mais visitadas