dicas de performance -...

13
Dicas de Performance Objetivo Este documento tem como objetivo informar algumas dicas rápidas de performance que podem ser aplicadas no dia-a-dia. As regras são simples e seus efeitos, isoladamente, podem não apresentar grandes resultados, entretanto, seguindo a uma maior quantidade de regras, a melhoria de performance é considerável. Muito dos problemas envolvem uso de comandos que causam impactos, enquanto outros problemas são causados por má utilização de comandos existentes, isto é, usar um comando que se substituído por outro melhora performance, podendo também diminuir consumo de memória. Um fator importante a ressaltar, é que a má performance pode ser resultado de um comando mal aplicado, bem como pelo consumo elevado de memória. Itens que serão abordados neste documento: Utilização do comando IF repetidamente. Utilização de blocos para agrupar comandos. Utilização do comando CASE. Utilização do comando IF para o uso do método LOAD-MOUSE-POINTER. Testes de variáveis lógicas. Utilização do comando CAN-FIND. Redução de transações. LOCK de registros Escopo de registros Não utilizar WORKFILES Utilização de TEMP-TABLE do tipo global. Utilização do parâmetro NO-UNDO em definição de variáveis e TEMP-TABLES. Limpeza de registros nas TEMP-TABLES Regras para utilização de índice Truques para economizar BANDWIDTH Quanto menos acesso melhor Use o comando ASSIGN

Upload: dangque

Post on 09-Dec-2018

218 views

Category:

Documents


1 download

TRANSCRIPT

Dicas de Performance

Objetivo Este documento tem como objetivo informar algumas dicas rápidas de performance que podem ser

aplicadas no dia-a-dia. As regras são simples e seus efeitos, isoladamente, podem não apresentar grandes resultados, entretanto, seguindo a uma maior quantidade de regras, a melhoria de performance é considerável.

Muito dos problemas envolvem uso de comandos que causam impactos, enquanto outros problemas são causados por má utilização de comandos existentes, isto é, usar um comando que se substituído por outro melhora performance, podendo também diminuir consumo de memória.

Um fator importante a ressaltar, é que a má performance pode ser resultado de um comando mal aplicado, bem como pelo consumo elevado de memória.

Itens que serão abordados neste documento:

Utilização do comando IF repetidamente.

Utilização de blocos para agrupar comandos.

Utilização do comando CASE.

Utilização do comando IF para o uso do método LOAD-MOUSE-POINTER.

Testes de variáveis lógicas.

Utilização do comando CAN-FIND.

Redução de transações.

LOCK de registros

Escopo de registros

Não utilizar WORKFILES

Utilização de TEMP-TABLE do tipo global.

Utilização do parâmetro NO-UNDO em definição de variáveis e TEMP-TABLES.

Limpeza de registros nas TEMP-TABLES

Regras para utilização de índice

Truques para economizar BANDWIDTH

Quanto menos acesso melhor

Use o comando ASSIGN

2

Utilização do comando IF repetidamente

O comando IF é um dos piores no ponto de vista de performance, entretanto, sua utilização é inevitável. Porém, é possível, em alguns pontos, fazer um melhor uso deste comando. Caso não seja possível substituir o comando IF por outro comando (CASE por exemplo), por motivos de lógica de programação, o uso adequado já auxilia na performance. A substituição dos comandos IF´S colocados um após o outro por uma encadeação do comando pode melhorar de maneira considerável a performance, isto é:

Exemplo de código “a ser melhorado”: IF <condição 1> THEN DO:

comandos...

END.

IF <condição 2> THEN DO:

comandos...

END.

IF <condição 3> THEN DO:

comandos...

END.

IF <condição 4> THEN DO:

comandos...

END.

IF <condição 5> THEN DO:

comandos...

END.

Exemplo de código “performático”: IF <condição 1> THEN DO:

comandos...

END.

ELSE

IF <condição 2> THEN DO:

comandos...

END.

ELSE

IF <condição 3> THEN DO:

comandos...

END.

ELSE

IF <condição 4> THEN DO:

comandos...

END.

ELSE

IF <condição 5> THEN DO:

comandos...

END.

Desta maneira, as condições 2,3,4 e 5 só serão executadas caso necessário, enquanto que no

primeiro caso, todas as condições são executadas. É bom levar em consideração que este exemplo depende, logicamente, da necessidade do

programa. Se for possível fazer a troca deste IF por um comando CASE, a performance pode ser melhorada.

3

Utilização de blocos para agrupar comandos A utilização de blocos para agrupar comandos, pode:

aumentar desnecessariamente o arquivo compilado (RCODE)

acarreta um aumento de gravações no LBI (local before image), quando os comandos que estão nele são atualizações de registros (gera sub-transação) ou de variáveis SEM a cláusula no-undo (controle de sub-transação)

Exemplo de Código “a ser melhorado”: IF <condição> THEN DO:

ASSIGN VAR1 = <valor 1>

VAR2 = <valor 2>

VAR3 = <valor 3>.

END.

ELSE DO:

ASSIGN VAR1 = <valor 4>

VAR2 = <valor 5>

VAR3 = <valor 6>.

END.

Exemplo de Código “performático”: IF <condição> THEN

ASSIGN VAR1 = <valor 1>

VAR2 = <valor 2>

VAR3 = <valor 3>.

ELSE

ASSIGN VAR1 = <valor 4>

VAR2 = <valor 5>

VAR3 = <valor 6>.

É importante ressaltar que neste caso, existe apenas um comando após o THEN e/ou ELSE, ou

seja, é desnecessária a utilização da estrutura DO...END. Entretanto, é necessário tomar cuidado em caso de chamada de INCLUDE numa estrutura IF...THEN. Como não é possível saber o que há dentro da INCLUDE, por precaução, é aconselhável utilizar o bloco.

Exemplo: IF <condição> THEN DO:

{INCLUDE}

END.

ELSE DO:

{INCLUDE2}

END.

Utilização do comando CASE Como já foi dito, a utilização do comando IF encadeado pode melhorar a performance em relação a

utilização de comandos IF repetidos, mas, ainda podem causar um impacto na performance de um programa.

Caso seja possível, é aconselhável utilizar o comando CASE no lugar dos comandos IF existentes.

4

Trocar: IF <condição 1> THEN DO:

comandos...

END.

ELSE

IF <condição 2> THEN DO:

comandos...

END.

ELSE

IF <condição 3> THEN DO:

comandos...

END.

Por: CASE c-campo:

WHEN “teste” THEN Comando...

WHEN “aluno” THEN Comando...

WHEN “compr” THEN Comando...

OTHERWISE Comando

END CASE.

Utilização do comando IF para o uso do método LOAD-MOUSE-POINTER Após alguns testes, foi percebido que a linha de comando: IF CAMPO:LOAD-MOUSE-POINTER("<DIRETÓRIO\ARQUIVO>") IN FRAME {&FRAME-NAME} THEN.

Pode ser substituída por:

CAMPO:LOAD-MOUSE-POINTER("<DIRETÓRIO\ARQUIVO>") IN FRAME {&FRAME-NAME}.

Aparentemente o ganho com esta troca pode parecer pequeno, mas levando em

consideração que muitos programas utilizam várias vezes esta técnica, a somatória destes pequenos ganhos pode vir a ser considerável.

Teste de variáveis lógicas

As comparações realizadas com variáveis lógicas em comandos, como por exemplo, as condições em um comando IF, são mais rápidas se não utilizam o sinal de igualdade para expressar a condição desejada.

Exemplos:

Exemplo de código “a ser melhorado”: IF <variável ou campo lógico> = YES THEN DO:

Comandos ...

END.

Exemplo de código “performático”: IF <variável ou campo lógico> THEN DO:

Comandos ...

END.

5

Utilização do comando CAN-FIND A utilização do comando CAN-FIND retorna TRUE ou FALSE quando utilizado, isto é,

existe apenas a verificação se o registro existe ou não. O registro pesquisado não fica habilitado para nenhuma operação, nem mesmo para leitura. Ao contrário do comando FIND que pode tornar o registro habilitado até mesmo para escrita.

Porém, o principal ganho para a melhoria da performance, é que o comando CAN-FIND retorna apenas um valor lógico, enquanto que o comando FIND busca todo o registro, isto é, aumenta o tráfego de rede fazendo I/O e aplicando controle de LOCK sobre o registro, desnecessariamente.

A principal funcionalidade do comando CAN-FIND é a necessidade de saber se um registro existe ou não, como por exemplo, em um cadastro. Ao verificar se a chave informada já existe, não é necessário trazer todo o registro, somente a informação de sua existência.

Exemplo:

Exemplo de Código “a ser melhorado”: FOR EACH <supertabela> no-lock:

FIND <tabela> WHERE <tabela>.<campo-chave> = <VALOR> no-lock.

IF NOT AVAILABLE <tabela> THEN DO:

CREATE <tabela>.

ASSIGN <tabela>.<campo-chave>

<tabela>.<demais-campos>.

END.

Exemplo de Código “performático”: FOR EACH <supertabela> no-lock:

IF NOT CAN-FIND(<tabela> WHERE <tabela>.<campo-chave> = <VALOR>)

THEN DO:

CREATE <tabela>.

ASSIGN <tabela>.<campo-chave>.

END.

Redução de transações Esse é o item mais importante na questão performance. A redução de transações significa

mais memória livre e menos registros bloqueados. Entretanto, para diminuir as transações, existe um aumento na complexidade da codificação dos programas.

Será descrito a seguir algumas dicas para diminuir transações: Para cada agrupamento de comandos que façam alteração de informações em um banco

de dados, é criado uma transação no escopo do bloco atual que pode ser o programa como um todo ou um laço(<block header> TRANSACTION: ... END.).

Regras para verificação de transações analisando o código fonte: As transações são geradas em tempo de compilação, é comum analisar-se o código e achar que determinado código não está gerando travamento de registro porque a rotina não passa por ali, o que NÃO é verdadeiro. O Progress cria transações para o primeiro bloco acima de uma comando FIND ... EXCLUSIVE-LOCK, ou ASSIGN/UPDATE com controle de erro (ON ENDKEY, ON ERROR)

6

Exemplos:

Uma grande transação: ... /* Início do programa – Não acessa o banco de dados */ DO <var1> = 1 TO 1000:

CREATE <tabela>.

ASSIGN <tabela>.<campo> = <VALOR>.

END.

... /* Finalização do programa – Não acessa o banco de dados */

Para este exemplo como não existe bloco superior com controle a transação deste

programa fica no escopo do programa e bloqueia 1000 registros.

Uma pequena transação: ... /* Início do programa – Não acessa o banco de dados */ DO <var1> = 1 TO 1000:

DO TRANSACTION:

CREATE <tabela>.

ASSIGN <tabela>.<campo> = <VALOR>.

END.

END.

... /* Finalização do programa – Não acessa o banco de dados */

A transação deste programa é menor, pois fica no escopo da transação (DO

TRANSACTION: ... END.) e bloqueia apenas 1 registro. Para isto é consumido menos memória e menos controle de .BI do que no exemplo anterior.

Problema comum: ... /* Início do programa – Não acessa o banco de dados */ IF <condição> THEN DO:

FIND <tabela> EXCLUSIVE-LOCK.

UPDATE <tabela>.

END.

FOR EACH <tabela_2> EXCLUSIVE-LOCK:

ASSIGN <tabela_2>.<campo> = <VALOR>.

END.

... /* Finalização do programa – Não acessa o banco de dados */

No exemplo acima TODOS os registros da <tabela_2> ficarão travados devido ao fato do

comando FIND...EXCLUSIVE-LOCK gerar uma transação forçando o programa a ser uma transação.

Forma de corrigir: ... /* Início do programa – Não acessa o banco de dados */ IF <condição> THEN DO TRANSACTION:

FIND <tabela> EXCLUSIVE-LOCK.

UPDATE <tabela>.

END.

FOR EACH <tabela_2> EXCLUSIVE-LOCK:

ASSIGN <tabela_2>.<campo> = <VALOR>.

END.

... /* Finalização do programa – Não acessa o banco de dados */

7

Ao diminuir-se o tamanho da transação para o FIND...EXCLUSIVE-LOCK o programa deixa de ser transação e apenas o registro que estiver em memória dentro do FOR EACH estará travado (1 por vez) .

Comando REPEAT: É considerado um laço simples, aquele que não tiver envolvimento com transações. O

comando REPEAT cria por default uma transação:

Transação desnecessária: REPEAT <VAR> = 1 TO 100:

ASSIGN <variável> = <VALOR>.

DISPLAY ...

END.

Foi criado desnecessariamente transações, ocupando então memória.

Correção: DO <VAR> = 1 TO 100:

ASSIGN <variável> = <VALOR>.

DISPLAY ...

END.

Não foi criado nenhuma transação, consumindo menos memória. Para saber exatamente quais as transações em um programa pode-se utilizar a opção

LISTING na compilação do código e verificar em quais linhas e blocos o progress esta reconhecendo como transação

Ex.: compile /cpp/programa.p listing c:/temp/trans.txt O Progress irá gerar um arquivo “trans.txt” com o código do programa e seus includes

incorporados e após isto colocará a análise de quais blocos são ou não transação. Ex. de arquivo gerado pelo compile listing com transação na procedure (programa

mau escrito) {} Line Blk

-- ---- ---

1 DEF VAR l-testa AS LOG NO-UNDO.

2

3 1 IF l-testa THEN DO:

4 1 FIND FIRST ITEM EXCLUSIVE-LOCK.

5 1 UPDATE ITEM.it-codigo = ITEM.it-codigo.

6 END.

7

8 1 FOR EACH man_docto EXCLUSIVE-LOCK:

9 1 ASSIGN man_docto.cdn_fabrica = man_docto.cdn_fabrica.

10 END.

File Name Line Blk. Type Tran Blk. Label

-------------------- ---- --------- ---- --------------------------------

c:\temp\teste.p 0 Procedure Yes

Buffers: mgind.item

c:\temp\teste.p 3 Do No

c:\temp\teste.p 8 For Yes

Buffers: grdind.man_docto

O programador deve tomar cuidado para não criar transações dentro de outra, pois a sub-

transação NÃO será liberada até que a transação seja concluída. Neste caso o programador receberá a mensagem abaixo na compilação

** WARNING--TRANSACTION keyword given within actual transaction level.

8

LOCK de registros O Progress possui 3 controles de LOCK (trava de registro), são eles . NO-LOCK . SHARE-LOCK . EXCLUSIVE-LOCK NO-LOCK Obtém o registro somente para leitura dos dados, utilizar sempre em relatórios para não

esperar pelos registros que estão sendo atualizados ou criados. SHARE-LOCK Obtém o registro para leitura e impossibilita outros usuários de aplicar leitura como

EXCLUSIVE-LOCK, quase nunca utilizado EXCLUSIVE-LOCK Obtêm o registro para alteração do mesmo, outros usuários não podem atualizar o mesmo

registro até que este seja liberado Quando usuário tenta acessar um registro com exclusive-lock e que está sendo atualizado

por outro usuário, este espera até que o registro seja liberado. Para não esperar até que outro usuário libere o registro o usuário pode trabalhar apenas com os registros NÃO travados ignorando os que estão sendo atualizados por outros usuários.

Exemplo de acesso apenas a registros “não travados”: FOR EACH <tabela> NO-WAIT EXCLUSIVE-LOCK:

UPDATE <tabela>.<campo> = “teste”.

END:

Ou FIND FIRST <tabela> NO-WAIT EXCLUSIVE-LOCK.

IF AVAILABLE <tabela> THEN UPDATE <tabela>.<campo> = “teste”.

Escopo de registros O escopo do registro é o tempo em que o registro está disponível no programa ou entre

programas. O escopo do registro pode ser FORTE ou FRACO O escopo FRACO, é comumente utilizado, onde o programa deixa para o Progress o

controle da disponibilidade do registro no programa

Exemplo de escopo FRACO: <pedaço do código>

DO TRANSACTION:

FIND FIRST <tabela> EXCLUSIVE-LOCK.

UPDATE <tabela>.<campo> = “teste”.

END.

DISPLAY <tabela>.<campo>.

<pedaço do código>

No exemplo acima o Progress mantém o registro disponível após o final da transação.

9

Exemplo de escopo FORTE: <pedaço do código>

DO TRANSACTION for <tabela>:

FIND FIRST <tabela> EXCLUSIVE-LOCK.

UPDATE <tabela>.<campo> = “teste”.

END.

DISPLAY <tabela>.<campo>.

<pedaço do código>

No exemplo acima o Progress NÂO mantém o registro disponível após o final da

transação e irá ocasionar um erro de compilação para este código Qual a utilização do escopo FORTE ? R.: Para forçar o Progress a manter o registro disponível em memória

Exemplo de escopo FRACO: FOR EACH <tabela>:

IF <condição>

THEN DO:

FIND FIRST <tabela1> NO-LOCK.

END.

END.

IF NOT AVAILABLE <tabela>

THEN DISPLAY <tabela1>.<campo>

Exemplo de escopo FORTE: DO FOR <tabela2>:

FOR EACH <tabela>:

IF <condição>

THEN DO:

FIND FIRST <tabela1> NO-LOCK.

END.

END.

IF NOT AVAILABLE <tabela>

THEN DISPLAY <tabela1>.<campo>

END.

No exemplo acima foi solicitado ao Progress que o escopo do registro ficasse disponível para o teste de available.

Não utilizar WORKFILES Não é aconselhável o uso de WORKFILES devendo ser trocados pelas TEMP-TABLES. Os WORKFILES são provenientes das versões anteriores de Progress e utilizam o limite

imposto pelos parâmetros –s –l, no caso do programa necessitar utilizar mais memória que o pré-alocado, o programa será interrompido com uma mensagem informando que você deve aumentar os parâmetros.

O uso de TEMP-TABLES elimina estes problemas por utilizar a quantidade necessária para a alocação de registros na TEMP-TABLE, quando a quantidade ultrapassa os valores informados pelos parâmetros a TEMP-TABLE começa então a utilizar no lugar da memória o HD como área de armazenamento.

10

Utilização de TEMP-TABLE do tipo global Não é aconselhável a utilização de TEMP-TABLE definida como uma variável global. O

consumo de memória causado por uma TEMP-TABLE pode ser muito grande, dependendo ainda, da quantidade de campos e registros. Esta variável será eliminada da memória somente ao fechar a sessão PROGRESS.

Neste caso, a performance do produto é afetada como um todo e não só de um programa apenas.

É possível, em muitos casos, substituir uma TEMP-TABLE global por uma TEMP-TABLE compartilhada (NEW SHARED e SHARED) ou por passagem de parâmetros.

Quando possível, limpar as temp-tables após o uso, visando minimizar a utilização de memória pelo programa.

Utilização do NO-UNDO em definição de variáveis e TEMP-TABLES Variáveis declaradas como NO-UNDO, não necessitam ser controladas pelo PROGRESS,

isto é, quando não é utilizado o parâmetro NO-UNDO, o arquivo *.LBI (local before image – este arquivo está no cliente) necessita controlar os valores armazenados pela variável. Isto aumenta I/O diminuindo a performance.

Normalmente, as variáveis não precisam ser controladas caso haja problemas com o sistema, sendo assim, não é necessário ficar armazenando seus valores.

Limpeza de registros nas TEMP-TABLES Uma das rotinas mais utilizadas nos programas que utilizam TEMP-TABLES é a

eliminação dos dados contidos na TEMP-TABLE para geração de uma nova massa de dados. Na versão 9 do Progress, foi implementado um novo comando (EMPTY TEMP-TABLE)

que torna a execução das rotinas de eliminação de TEMP-TABLES mais performática. Essa eliminação, quando for de TODOS os registros da TEMP-TABLE pode ser usada

utilizando a seguinte combinação de comandos.

Exemplo de Código “performático”: &IF integer(entry(1,proversion,".")) >= 9

&THEN

empty temp-table <temp-table>.

&ELSE

for each <temp-table>:

delete <temp-table>.

end.

&ENDIF

Regras para utilização de índice O Progress possui algumas regras para escolher o melhor índice a ser utilizado numa

consulta Este assunto é complexo, porêm vamos tentar passar os passos básicos efetuados pelo

progress para a escolha do índice e o que o programador pode fazer para forçar o uso de um índice (correto) na programação.

11

Para forçar o progress à utilizar o índice desejado o programador pode incluir a cláusula USE-INDEX no acesso ao registro

Forçando o uso do índice: for each <temp-table> USE-INDEX <nomedoindice> WHERE <condição>:

delete <temp-table>.

end.

Como o Progress escolhe o índice automaticamente:

utiliza o primeiro índice (por ordem alfabética) que satisfaz todos os campos da consulta

utiliza o índice que satisfaz mais campos da consulta

utiliza o índice primário para algum campo igual o da consulta

varre a tabela (full scan) Exemplo de índices numa tabela primario (primario)

campo A

combinado

campo A

campo B

campo C

campo D

sumarizado

campo A

campo B

Verificando o uso do índice: FOR EACH <tabela> WHERE

<tabela>.<campoA> = 1 and

<tabela>.<campoB> = 2 no-lock:

END.

O código acima utiliza o índice combinado, onde o correto para melhor performance seria

o índice sumarizado. Sempre que houverem mais de um índice que satisfaça a condição para

o acesso do registro deve-se forçar o uso do índice com menor número de campos. Para verificar qual o índice utilizado pelo Progress, pode-se usar a cláusula xref (Cross

Reference) no momento da compilação. Ex.: compile /cpp/programa.p xref c:/temp/xref.txt

Programa exemplo: DEF VAR l-testa AS LOG NO-UNDO.

IF l-testa THEN DO TRANSACTION:

FIND FIRST ITEM WHERE

ITEM.it-codigo = "TESTE" EXCLUSIVE-LOCK.

UPDATE ITEM.it-codigo = ITEM.it-codigo.

END.

FOR EACH man_docto WHERE

man_docto.cdn_fabrica = 7501 EXCLUSIVE-LOCK

BY man_docto.cdn_docto:

ASSIGN man_docto.cdn_fabrica = man_docto.cdn_fabrica.

END.

12

Segue abaixo o arquivo xref para o programa exemplo

c:\temp\teste.p c:\temp\teste.p 1 COMPILE c:\temp\teste.p

c:\temp\teste.p c:\temp\teste.p 1 CPINTERNAL ISO8859-1

c:\temp\teste.p c:\temp\teste.p 1 CPSTREAM ibm850

c:\temp\teste.p c:\temp\teste.p 1 STRING "l-testa" 7 NONE UNTRANSLATABLE

c:\temp\teste.p c:\temp\teste.p 4 STRING "item" 4 NONE UNTRANSLATABLE

c:\temp\teste.p c:\temp\teste.p 4 STRING "Item" 4 NONE TRANSLATABLE

c:\temp\teste.p c:\temp\teste.p 4 ACCESS mgind.item it-codigo

c:\temp\teste.p c:\temp\teste.p 4 STRING "TESTE" 5 NONE TRANSLATABLE

c:\temp\teste.p c:\temp\teste.p 4 SEARCH mgind.item codigo

c:\temp\teste.p c:\temp\teste.p 6 ACCESS mgind.item it-codigo

c:\temp\teste.p c:\temp\teste.p 6 ACCESS mgind.item it-codigo

c:\temp\teste.p c:\temp\teste.p 6 UPDATE mgind.item it-codigo

c:\temp\teste.p c:\temp\teste.p 9 STRING "man_docto" 9 NONE UNTRANSLATABLE

c:\temp\teste.p c:\temp\teste.p 9 STRING "Documento" 9 NONE TRANSLATABLE

c:\temp\teste.p c:\temp\teste.p 9 ACCESS grdind.man_docto cdn_fabrica

c:\temp\teste.p c:\temp\teste.p 9 SEARCH grdind.man_docto num_programa WHOLE-INDEX

c:\temp\teste.p c:\temp\teste.p 9 SORT-ACCESS grdind.man_docto cdn_docto

c:\temp\teste.p c:\temp\teste.p 11 ACCESS grdind.man_docto cdn_fabrica

c:\temp\teste.p c:\temp\teste.p 11 ACCESS grdind.man_docto cdn_fabrica

c:\temp\teste.p c:\temp\teste.p 11 UPDATE grdind.man_docto cdn_fabrica

c:\temp\teste.p c:\temp\teste.p 12 STRING "codigo" 6 NONE UNTRANSLATABLE

c:\temp\teste.p c:\temp\teste.p 12 STRING "num_programa" 12 NONE UNTRANSLATABLE

ACCESS access <nomedobanco>.<tabela> <nome_do_campo_referenciado> SORT-ACCESS sort-access <nomedobanco>.<tabela> <nome_do_campo_que_nao_esta_no_indice> indica que aqui pode estar acontecendo um problema performance SEARCH search <nomedobanco>.<tabela> <nome_do_índice_que_o_prog_utilizou> WHOLE-INDEX – índice que o progress gerou para satisfazer a consulta STRING string <string> <tamanho_da_string> UPDATE update <nomedobanco>.<tabela> <nome_do_campo_atualizado>

Truques para economizar BANDWIDTH Um dos grandes problemas de performance é a transferência de quantidades maciças de

dados entre o servidor de banco de dados e o cliente que roda a aplicação. Para economizar fluxo de rede (BANDWIDTH) é interessante sempre que possível para

tabelas que possuam muitos campos (Ex. item), seja utilizado a cláusula FIELDS

Exemplo de Código “a ser melhorado”: FIND FIRST <supertabela> no-lock.

DISPLAY <supertabela>.<campo5>.

FOR EACH <supertabela> no-lock:

ASSIGN <variável> = <supertabela>.<campo1>.

END.

Exemplo de Código “performático”: FOR FIRST <supertabela> FIELDS (<campo5>) no-lock:

DISPLAY <supertabela>.<campo5>.

END.

13

FOR EACH <supertabela> FIELDS (<campo1>) no-lock:

ASSIGN <variável> = <supertabela>.<campo1>.

END.

Lembrando que numa rede ETHERNET trafega 1 (um) pacote por vez, a economia gerada

pelo uso contínuo desse artifício é enorme, o que diminui o número de colisões de pacotes.

Quanto menos acesso melhor Um dos problemas mais encontrados nos códigos é o acesso redundante à grandes

tabelas o que degrada a performance e aumenta o consumo de recursos do servidor de banco de dados.

Exemplo de Código “a ser melhorado”: FOR EACH <tabela>: /* possui 20.000 registros */

FIND <tabela_2> WHERE

<tabela_2>.<campo> = <tabela>.campo NO-LOCK.

DISPLAY <tabela>.<campo>

<tabela_2>.<campo>.

END.

Exemplo de Código “performático”: FOR EACH <tabela>

BREAK BY <tabela>.<campo>: /* possui 20.000 registros */

IF FIRST-OF(<tabela>.<campo>)

THEN DO:

FIND <tabela_2> WHERE

<tabela_2>.<campo> = <tabela>.campo NO-LOCK.

ASSIGN <variável> = <tabela2>.<campo>.

END.

/* uso do @ faz com que não seja preciso alterar o layout da frame */

DISPLAY <tabela>.<campo>

<variável> @ <tabela_2>.<campo>

END.

O código acima foi alterado para “economizar” acessos à segunda tabela e por

conseqüência aumentar a performance do programa.

Use o comando ASSIGN

Otimize a carga de valores em variáveis com o comando ASSIGN, pois além de ser mais

rápido, o R-CODE do programa fica menor, alocando menos memória na execução do programa.

Exemplo de Código “a ser melhorado”: w-campo1 = “texto”. /* Repare o ponto final aqui */

w-campo2 = w-empresa. /* Repare o ponto final aqui */

w-tipo = “A”. /* Repare o ponto final aqui */

Exemplo de Código “performático”: ASSIGN w-campo1 = “texto”

w-campo2 = w-empresa

w-tipo = “A. /* Repare o ponto final aqui */