Anda di halaman 1dari 17

Manual de Performance em Progress

Manual
De
Performance em
Banco de Dados
Progress







Manual de Performance em Progress



NDICE

VARIVEIS ................................................................................................... 3
BUFFER-COPY ....................................................................................................................................... 4
FIND CURRENT ................................................................................................................................. 6
TEMP-TABLES ................................................................................................................................... 6
USE-INDEX ............................................................................................................................................. 7


Manual de Performance em Progress



MANUAL PRTICO DE PERFORMANCE

INTRODUO

A melhoria de performance, tanto em PROGRESS quanto em qualquer outra
linguagem envolve normalmente uma srie de fatores. No existe nenhum comando mgico
que acrescentado a um programa vai torna-lo muito mais rpido.
Na maioria das vezes, uma melhoria na forma de funcionamento do programa,
tornando-o mais inteligente e menos repetitivo possibilita uma melhoria substancial de
performance.
Entretanto, mesmo os programas corretamente escritos podem se beneficiar de alguns
recursos que o PROGRESS disponibiliza para torna-los mais geis. So esses recursos que
sero analisados a seguir.


VARIVEIS

A menos que a aplicao no permita, utilize sempre variveis NO-UNDO, pois elas
no utilizam controle de transaes, evitando escritas no arquivo LBI local, o que melhora a
performance. Procure tambm evitar as variveis LIKE, a menos que essas variveis sejam
utilizadas para exibio de informaes na tela. Para variveis internas, utilize a declarao
AS, sem FORMAT nem LABEL.

DEF VAR c-it-codigo AS CHAR NO-UNDO.

Evite tambm as variveis SHARED, a no ser que a aplicao exija. Se as chamadas
a programas externos forem substitudas por PROCEDURES internas, a utilizao de variveis
SHARED/NEW SHARED torna-se desnecessria. Essa tcnica ser mostrada com mais
detalhes mais frente.
Quando forem utilizadas variveis do tipo EXTENT, inicialize seu contedo com apenas
um comando ASSIGN, ao invs de utilizar um loop, o que muito mais lento.

Certo:

DEF VAR c-it-codigo AS CHAR extent 10 NO-UNDO.
ASSIGN c-it-codigo = "A".

Errado:

DEF VAR c-it-codigo AS CHAR extent 10 NO-UNDO.
DEF VAR i-cont AS integer NO-UNDO.
DO i-cont = 1 TO 10:
ASSIGN c-it-codigo[i-cont] = "A".
END.



ASSIGN

Sempre utilize o comando ASSIGN para carregar valores para variveis/campos.
Procure agrupar o mximo de variveis possveis em um mesmo ASSIGN.

Certo:

ASSIGN c-it-codigo = "item-1"
i-op-codigo = 10
c-cod-roteiro = "rot-1".

Errado:

Manual de Performance em Progress




c-it-codigo = "item-1".
i-op-codigo = 10.
c-cod-roteiro = "rot-1".



BUFFER-COPY

Este um comando novo, introduzido na verso 8 do PROGRESS, que possibilita uma
boa melhoria de performance, quando bem utilizado. Ele realiza a cpia de valores entre dois
BUFFERS de registro, podendo trabalhar inclusive com TEMP-TABLES. Abaixo temos um
exemplo tpico da utilizao do BUFFER-COPY:

DEF TEMP-TABLE tt-item NO-UNDO LIKE item USE-INDEX codigo.
FOR EACH item NO-LOCK:
CREATE tt-item.
BUFFER-COPY item TO tt-item.
END.

O exemplo acima copia todos os campos da tabela item para uma TEMP-TABLE. Alm
de executar mais rapidamente, a possibilidade de erros de digitao muito menor. Basta
lembrar que a tabela item possui mais de 200 campos. Um detalhe que vale a pena mencionar,
que os campos da TEMP-TABLE precisam estar definidos exatamente com o mesmo nome
dos campos da tabela, pois o BUFFER-COPY no realiza substituio de campos por
similaridade. Por exemplo, o campo NR-ORD-PROD e NR-ORD-PRODU vo surtir o mesmo
efeito em um comando ASSIGN, mas iro falhar em um comando BUFFER-COPY. Este
comando tambm permite a utilizao das clusulas USING e EXCEPT, permitindo informar
quais os campos que devero ser copiados. Para maiores detalhes, conveniente consultar o
help.



FIELDS

A clusula FIELDS, tambm conhecida por FIELD-LIST, permite ao programador definir
quais os campos de determinada tabela um comando de busca ir trazer atravs da rede para
a mquina cliente. Este recurso foi introduzido pelo PROGRESS 8 para melhorar a
performance em sistemas cliente/servidor. Atravs dele possvel reduzir bastante o trfego de
rede e consequentemente a velocidade dos programas. A clusula FIELDS pode ser utilizada
com os comandos FOR (FOR EACH, FOR FIRST, FOR LAST) e nas definies de QUERYS.

Manual de Performance em Progress



FOR FIRST/LAST

Os comandos FOR FIRST e FOR LAST podem substituir os comandos FIND FIRST e
FIND LAST respectivamente. A grande vantagem do comando FOR possibilitar a utilizao
da clusula FIELDS, que permite definir quais os campos que sero enviados pela rede do
servidor para o cliente. A utilizao destes comandos deve ser feita com alguns cuidados:

-Caso a tabela a ser lida possua poucos campos e todos ou quase todos os campos sero
utilizados aps o comando FOR, no vantajoso utiliza-lo;
-Os campos que no forem includos na clusula FIELDS no estaro disponveis para uso
pelo programa, entretanto o PROGRESS NO emitir mensagens de erro em tempo de
compilao. Apenas sero emitidas mensagens de erro durante a execuo do programa;
-A utilizao do FOR com a clusula FIELDS vantajosa apenas em ambiente
Cliente/Servidor, onde os registros transitam pela rede. Em ambientes HOST BASED
(como o Magnus I), no apresentam nenhuma vantagem.
-Embora o comando permita, NUNCA deve ser utilizada a clusula BY, pois nem o FOR FIRST
e nem o FOR LAST realizam a ordenao antes de retornar o registro. A clusula BY pode
ser utilizada apenas com FOR EACH.
-Utilize FOR FIRST/FOR LAST apenas para leituras NO-LOCK. Para a leitura de registros que
sero atualizados, mais conveniente a utilizao do FIND EXCLUSIVE-LOCK.

A sintaxe mais comum para os comandos FOR FIRST/FOR LAST a seguinte:

FOR FIRST item FIELDS (it-codigo perm-saldo-neg pm-ja-calc)
WHERE item.it-codigo = c-it-codigo NO-LOCK: END.


FOR EACH

O comando FOR EACH tambm permite a utilizao da clusula FIELDS, o que agiliza
bastante a execuo deste comando. O exemplo abaixo cerca de 3 vezes mais rpido com a
clusula FIELDS:

FOR EACH item FIELDS (it-codigo) NO-LOCK:
END.

Procure aninhar o mximo de leituras possveis no mesmo comando.

Certo:

FOR EACH item FIELDS (it-codigo) NO-LOCK,
FIRST estrutura FIELDS (it-codigo)
WHERE estrutura.it-codigo = item.it-codigo NO-LOCK:
DISP estrutura.it-codigo.
END.

Errado:

FOR EACH item FIELDS (it-codigo) NO-LOCK:
FIND estrutura WHERE
estrutura.it-codigo = item.it-codigo NO-LOCK NO-ERROR.
IF avail estrutura THEN DISP estrutura.it-codigo.
END.

Lembre-se que a clusula FIELDS e a clusula NO-LOCK devem ser informadas para
cada componente do FOR EACH.
Quando for realizar a atualizao de registros, dentro de um FOR EACH, onde apenas
alguns registros sero atualizados, procure realizar um FOR EACH com a clusula NO-LOCK e
um FIND EXCLUSIVE-LOCK apenas para os registros que sero atualizados.

FOR EACH item FIELDS (it-codigo pm-ja-calc) NO-LOCK:

Manual de Performance em Progress



IF item.pm-ja-calc THEN DO:
FIND b-item WHERE ROWID (b-item) = ROWID (item) EXCLUSIVE-LOCK:
ASSIGN b-item.log-1 = yes.
END.
DISP item.it-codigo.
END.

Lembre-se de utilizar um BUFFER do registro para realizar a atualizao, seno o
PROGRESS vai emitir uma mensagem de erro.



FIND CURRENT

O comando FIND CURRENT pode ser utilizado para realizar a atualizao de um
registro j tenha sido lido com um FOR FIRST.

FOR FIRST item FIELDS (it-codigo) NO-LOCK:
IF fn-altera-item (item.it-codigo) THEN DO:
FIND current item EXCLUSIVE-LOCK.
ASSIGN item.log-1 = yes.
END.


TEMP-TABLES

As TEMP-TABLES, se utilizadas corretamente, possibilitam grande auxlio na melhora
de performance dos programas em PROGRESS.
Procure defini-las como NO-UNDO, a menos que seja realmente necessrio manter o
controle sobre as alteraes realizadas dentro das transaes. A utilizao da clusula NO-
UNDO, alm de torna-la mais rpida, ocupa menos espao em disco na estao do cliente.
Procure ser o mais mesquinho possvel na criao de ndices, pois eles tornam a
incluso de registros mais lenta. Por outro lado, na grande maioria das vezes, excelente
definir um ndice primrio e nico baseado nos FINDS que forem executados no programa.
No utilize os comandos FOR FIRST, FOR LAST e CAN-FIND para TEMP-TABLES,
pois eles no iro proporcionar nenhum ganho de performance, afinal todas as informaes da
TEMP-TABLE esto armazenadas localmente e no iro transitar pela rede. Da mesma forma,
no necessrio utilizar as clusulas NO-LOCK, SHARE-LOCK ou EXCLUSIVE-LOCK, pois
no existe lock de registros para TEMP-TABLES. O PROGRESS simplesmente vai ignorar
essas clusulas.
O CAN-FIND, s vezes, no retorna o registro da temp-table. Use FIND.
Sempre que uma TEMP-TABLE for passada como parmetro, esquea seu ROWID,
pois ele ser alterado. Os FINDS com ROWID so os mais rpidos, mas se a TEMP-TABLE for
passada como parmetro ser necessrio utilizar o ndice primrio da TEMP-TABLE para
posiciona-la.
Procure evitar a criao de TEMP-TABLES LIKE, pois apesar de precisar de menos
trabalho para defini-las, elas copiam todas as definies da tabela original, inclusive os ndices.
Apenas utilize TEMP-TABLES LIKE se realmente precisar de todos ou de quase todos os
campos da tabela original.
Se FOR realmente necessria a criao de uma TEMP-TABLE LIKE, utilize a clusula
USE-INDEX, o que far com que apenas o ndice informado seja trazido da tabela original para
a TEMP-TABLE.

DEF TEMP-TABLE tt-item NO-UNDO LIKE item USE-INDEX codigo.

Procure evitar a utilizao de TEMP-TABLES SHARED e NUNCA utilize TEMP-
TABLES GLOBAL SHARED.




Manual de Performance em Progress



USE-INDEX

Procure utilizar a clusula USE-INDEX com FIND, FOR EACH e outros comandos de
busca de registros, sempre que voc quiser forar a utilizao de um ndice. Algumas vezes o
PROGRESS NO ir selecionar o melhor ndice para satisfazer a consulta com a melhor
performance possvel. Se usar o USE-INDEX, e caso o ndice seja modificado, reavalie o seu
programa, pois ele poder no mais estar aproveitando ao mximo o ndice selecionado, se
forem includos/modificados ou eliminados campos que faziam parte do ndice originalmente.


ROWID

As buscas utilizando o ROWID so as mais eficientes. Sempre que possvel, procure
utilizar o ROWID da tabela para realizar uma busca. Se o programa permitir, armazene o
ROWID utilizado em uma TEMP-TABLE para utilizao posterior, caso os mesmos registros
sejam acessados vrias vezes durante a execuo do mesmo.


RUN

O comando RUN permite a execuo de PROCEDURES internas, programas externos
e chamadas para DLLs criadas atravs de outras linguagens. O objetivo deste tpico
analisar as chamadas para programas externos.
Todo programa externo (.P ou .W) reside em disco, no sendo carregado para a
memria no momento da execuo do programa pai. Eles sero apenas trazidos para a
memria quando da execuo do comando RUN. Dependendo do tamanho do programa a ser
chamado, de onde ele est localizado (em um servidor de arquivos da rede, por exemplo) e da
velocidade do meio de armazenamento/transporte utilizado, esse tempo pode ser bastante
longo. O PROGRESS dispe de alguns parmetros de inicializao da seo (por exemplo o
q) que diminuem o tempo necessrio para a execuo de uma chamada externa. Entretanto,
mesmo com um ambiente otimizado, as chamadas externas devem ser evitadas ao mximo.
Um dos mais promissores substitutos das chamadas para programas externos so as
PROCEDURES internas (PIs), que sero tratadas a seguir. Alm disso, dependendo da
situao, uma boa soluo pode ser a utilizao de INCLUDES ou a execuo de uma
chamada em modo persistente, que tambm sero tratadas a seguir. Como comparativo de
performance, seguem abaixo dois exemplos de cdigo. O primeiro utiliza uma chamada para
programa externo e o outro utiliza uma PROCEDURE interna.

Exemplo 01:

/* A1.P */
DEF NEW SHARED TEMP-TABLE tt-item NO-UNDO LIKE item USE-INDEX codigo.

FOR EACH item NO-LOCK:
RUN B1.p (BUFFER item).
END.

/* B1.P */
DEF SHARED TEMP-TABLE tt-item NO-UNDO LIKE item USE-INDEX codigo.
DEF param BUFFER b-item FOR item.

CREATE tt-item.
BUFFER-COPY b-item TO tt-item.

Exemplo 02:

DEF TEMP-TABLE tt-item NO-UNDO LIKE item USE-INDEX codigo.

FOR EACH item NO-LOCK:
RUN pi-grava (BUFFER item).

Manual de Performance em Progress



END.

PROCEDURE pi-grava.
DEF param BUFFER b-item FOR item.
CREATE tt-item.
BUFFER-COPY b-item TO tt-item.
end PROCEDURE

O primeiro exemplo executado em 29 segundos e o outro em 23 segundos. Vale
lembrar que o sub-programa B1.P bem pequeno. Em condies reais, quanto maior o sub-
programa, maior ser a diferena de performance.



PROCEDURES

As PROCEDURES internas so uma das mais eficazes armas para melhoria de
performance. Alm de serem chamadas mais rapidamente, possuem uma srie de outras
vantagens:

-Podem receber um nome mais explicativo com relao funo que realizam. Por exemplo, o
nome PI-CRIA-RESERVAS-ORDEM bem mais esclarecedor do que CPP/CP0302b.p.
-Como elas esto no corpo do programa, todos os BUFFERS e variveis que forem declaradas
no programa principal podero ser acessadas pela PI, no precisando receber parmetros
e nem variveis SHARED.
-Permite a definio de variveis e BUFFERS locais, o que as torna perfeitas para execues
recursivas.
-Apesar de estarem no corpo do programa, cada PROCEDURE carregada em seu prprio
segmento executvel, o que permite que cada uma delas tenha at 64KBYtes de tamanho,
como qualquer programa externo.

Uma tcnica que torna a programao com PROCEDURES extremamente fcil e
estruturada, utilizada em algumas APIs do mdulo de Produo do EMS 2.0, como a API de
criao de ordens de produo (CPAPI301) e de reporte repetitivo (CPAPI009). Essa tcnica
consiste em definir o cdigo das PROCEDURES em INCLUDES e depois incorporar essas
INCLUDES ao corpo principal do programa, o que acaba tornando-o bem pequeno e permite
uma grande estruturao no cdigo.



INCLUDES

As INCLUDES podem ser utilizadas para substituir as chamadas para programas
externos e tambm para PROCEDURES internas, com algumas restries. Como o cdigo
contido nas INCLUDES incorporado ao programa, elas permitem a execuo do programa
em velocidade mxima, sem perdas de performance por causa de chamadas para programas
externos ou PROCEDURES. Entretanto, elas aumentam o tamanho do programa, muitas vezes
superando o limite de 64KBYtes por segmento executvel. Uma regra bsica para as
INCLUDES que devem existir poucas chamadas repetidas para elas dentro dos programas e
que devem preferencialmente ser utilizadas em locais extremamente crticos em relao
performance.



PROGRAMAS PERSISTENTES

Uma boa idia da PROGRESS. Um programa sendo executado de forma persistente
nada mais que um programa externo, rodado atravs do comando RUN e que retorna um
HANDLE para o programa chamador, permanecendo ativo na memria. Atravs desse
HANDLE possvel a execuo de qualquer PROCEDURE interna do programa, como se elas

Manual de Performance em Progress



fizessem parte do cdigo original do programa pai. Um exemplo bastante conhecido de
programa persistente o UT-ACOMP.P, que chamado de forma persistente e depois permite
a execuo de vrias PROCEDURES como a PI-ACOMPANHAR e PI-INICIALIZAR.
Infelizmente, o recurso de execuo persistente no muito utilizado pelo EMS. Atravs dele
seria possvel uma maior separao da interface das regras de negcio, disponibilizando
PROCEDURES dentro das APIs para realizao de validaes, verificaes de saldo e outras
tarefas que so realizadas pelos programas com interface antes da efetiva chamada da API.
Alm disso, o PROGRESS permite a execuo de programas persistentes em um
servidor RPC, realizando AS chamadas das PROCEDURES diretamente ao servidor, de forma
transparente para o programa, tornando a execuo ainda mais rpida.
A sintaxe mais comum para execues persistentes :

RUN cpp/cpapi001.p PERSISTENT SET h-handle.


CAN-FIND

A funo CAN-FIND retorna um valor lgico YES caso encontre o registro informado. O
CAN-FIND deve sempre ser utilizado quando apenas necessria a confirmao da existncia
ou no do registro, pois executa de forma mais rpida do que o FIND ou o FOR FIRST. Como
a verificao da existncia do registro feita no servidor, no haver nenhuma informao
transitando pela rede a no ser um valor lgico YES ou NO, o que bem mais rpido do que o
envio de um ou mais campos da tabela como acontece com o FIND ou o FOR FIRST.



SHARE-LOCK

Evite utiliza-lo. Como o default do PROGRESS para os comandos FIND e FOR
SHARE-LOCK, deve-se sempre acrescentar AS clusulas NO-LOCK ou EXCLUSIVE-LOCK
quando for o caso.



BUFFER

Sempre que for necessria a utilizao de um registro em uma PROCEDURE ou um
sub-programa externo, utilize a passagem do BUFFER como parmetro, em vez de passar o
ROWID e realizar um FIND por esse ROWID.




Certo:

/* A1.P */
FOR FIRST item FIELDS (it-codigo) NO-LOCK: END.
RUN B1.P (BUFFER item).


/* B1.P */
DEF param BUFFER b-item FOR item.
DISP b-item.it-codigo.


Errado:

/* A1.P */
FOR FIRST item FIELDS (it-codigo) NO-LOCK: END.
RUN B1.P (INPUT ROWID (item)).


Manual de Performance em Progress




/* B1.P */
DEF INPUT param rw-item AS ROWID NO-UNDO.
FIND item WHERE ROWID (item) = rw-item NO-LOCK.
DISP item.it-codigo.


Deve-se lembrar que se um registro lido com NO-LOCK, ele permanecer com o
mesmo estado tambm no programa B1.P. O mesmo vale para a clusula FIELDS, que
mantm o efeito no sub-programa. No exemplo acima, apenas o campo it-codigo est
disponvel tanto no A1.P quanto no B1.P.
Uma restrio utilizao de PARAM BUFFER que no possvel passar o BUFFER
para programas executados via RPC.



WORK-FILES

Os WORK-FILES ou WORK-TABLES possuem algumas vantagens de performance em
relao s TEMP-TABLES, entretanto possuem vrias deficincias que restringem o seu uso a
apenas algumas situaes. A principal deficincia no permitir a utilizao de ndices e nem a
realizao de FIND para registros especficos, permitindo apenas a movimentao seqencial,
com FIND NEXT/PREV/FIRST/LAST embora permita o posicionamento de forma aleatria
utilizando-se o ROWID. Como vantagem, destaca-se a velocidade na criao de registros, um
pouco superior das TEMP-TABLES. Como os WORK-FILES so armazenados
exclusivamente em memria, no possvel a utilizao dos mesmos para armazenamento de
uma grande quantidade de registros. Outra desvantagem no poderem ser passados como
parmetros.
A utilizao mais bvia para os WORK-FILES seria em uma aplicao que iria criar
registros de forma seqencial, realizando depois a leitura dos mesmos tambm de forma
seqencial, na mesma ordem.

Manual de Performance em Progress



CASE

Um comando extremamente interessante e tambm pouco utilizado. O CASE mais
rpido que uma srie de comandos IF...THEN...ELSE aninhados e possibilita uma estruturao
maior no programa.

Certo:

CASE n:
WHEN 1 THEN RUN pi-proc-1.
WHEN 2 THEN RUN pi-proc-2.
OTHERWISE RUN pi-proc-3.
END CASE.


Errado:

IF n = 1 THEN
RUN pi-proc-1.
ELSE IF n = 2 THEN
RUN pi-proc-2
ELSE RUN pi-proc-3.




IF...THEN...ELSE

O comando IF, em algumas situaes pode ser substitudo pelo CASE. Em outras no.
Uma forma de utilizao que embora facilite bastante tem reflexos negativos na performance
a combinao dos comandos ASSIGN e IF (em determinadas situaes). O exemplo abaixo
ilustra bem isso:

Certo:

IF x = 1 THEN
ASSIGN n = 0.


Errado:

ASSIGN n = IF x = 1 THEN 0 ELSE n.

Alm disso, deve-se evitar a utilizao das constantes lgicas com o comando IF,
conforme ilustrado abaixo:

Certo:

IF l-teste THEN RUN pi-teste.
IF NOT l-teste THEN RUN pi-nao-teste.

Errado:

IF l-teste = yes THEN RUN pi-teste.
IF l-teste = no THEN RUN pi-nao-teste.

Obs.: Nos comandos de busca (FIND, FOR) no deve ser utilizado o operador NOT,
sob pena do PROGRESS realizar uma busca em toda a tabela.




Manual de Performance em Progress



INDEXED-REPOSITION

Essa opo, existente nas QUERYS e SMART-QUERYS do PROGRESS, torna a
navegao muito mais rpida. Ela no pode ser utilizada se houverem JOINS na QUERY.

Em Options selecione Fields Used, dando um duplo-clique na coluna Returned, trocando
de All Fields para Fields Used. Assim, retorno do banco somente os campos selecionados.


TRIGGERS

Existem muitas tabelas importantes do EMS que possuem TRIGGERS de WRITE,
CREATE e DELETE. Uma das mais conhecidas a tabela item que possui uma TRIGGER de
WRITE bastante complexa. Esses programas so executados toda vez que o evento
correspondente executado em uma tabela. Por exemplo, a TRIGGER de WRITE do item
executada toda vez que alguma informao alterada nessa tabela. Em muitos casos isso
reduz bastante a performance. Dependendo da aplicao, os campos a serem modificados no
tem qualquer interferncia na lgica da TRIGGER, entretanto ela executada assim mesmo.
Uma melhoria de performance considervel pode ser conseguida desabilitando-se as
TRIGGERS das tabelas que esto sendo atualizadas. Uma forma de fazer isso pode ser vista
abaixo:

ON WRITE OF item OVERRIDE DO: END.

Este cdigo ir criar uma TRIGGER vazia que sobrepe a execuo da TRIGGER
original, evitando que esta seja executada.
Obs.: Tenha cuidado na hora de desabilitar as TRIGGERS. Verifique se realmente isso
vai prover um ganho significativo de performance e se voc no estar desativando regras de
negcio importantes para o produto.



Manual de Performance em Progress




NDICES

A correta utilizao dos ndices das tabelas uma das formas mais eficientes de
melhoria de performance. Existem vrias regras para um bom aproveitamento dos ndices.
Vamos analisar todas elas:

-Quando realizar a busca de um registro utilizando um ndice composto de vrios campos,
sempre procure utilizar EQUALITY MATCHES, ou seja, condies com o sinal de igual
(=), na mesma seqncia em que so definidos no ndice.

Ex.: ndice cdigo, da tabela oper-ord, do banco MGIND: nr-ord-prod, it-codigo, cod-roteiro,
op-codigo.

Procure sempre utilizar o mximo possvel de EQUALITY MATCHES, a partir do primeiro
componente do ndice:


Adequado:
FOR EACH oper-ord
WHERE oper-ord.nr-ord-prod = i-nr-ord-prod
NO-LOCK:

Melhor:
FOR EACH oper-ord
WHERE oper-ord.nr-ord-prod = i-nr-ord-prod
AND oper-ord.it-codigo = c-it-codigo
NO-LOCK:

Rpido:
FOR EACH oper-ord
WHERE oper-ord.nr-ord-prod = i-nr-ord-prod
AND oper-ord.it-codigo = c-it-codigo
AND oper-ord.cod-roteiro = c-cod-roteiro
NO-LOCK:

Muito Rpido:
FOR EACH oper-ord
WHERE oper-ord.nr-ord-prod = i-nr-ord-prod
AND oper-ord.it-codigo = c-it-codigo
AND oper-ord.cod-roteiro = c-cod-roteiro
AND oper-ord.op-codigo = i-op-codigo
NO-LOCK:



Evite:

FOR EACH oper-ord
WHERE oper-ord.nr-ord-prod = i-nr-ord-prod
AND oper-ord.cod-roteiro = c-cod-roteiro
AND oper-ord.op-codigo = i-op-codigo
NO-LOCK:

No exemplo acima, o PROGRESS apenas utiliza o primeiro componente do ndice, no
podendo utilizar os demais por causa da quebra de seqncia nos campos do ndice. Esse
exemplo especialmente lento, podendo ser inclusive mais lento do que o exemplo abaixo:

FOR EACH oper-ord
WHERE oper-ord.nr-ord-prod = i-nr-ord-prod
NO-LOCK:

Manual de Performance em Progress



IF oper-ord.cod-roteiro <> c-cod-roteiro or
oper-ord.op-codigo <> i-op-codigo THEN NEXT.

NUNCA realize uma busca sem utilizar pelo menos o primeiro campo de um ndice
qualquer da tabela, mesmo que os demais campos no correspondam aos campos do
ndice. No exemplo acima, nunca deveria ser realizado um FOR EACH na tabela oper-ord
sem a utilizao do campo nr-ord-prod, a no ser que exista outro ndice que permita esse
tipo de busca.

-INEQUALITY MATCHES (<>) devem ser evitados ao mximo, sob pena de obrigarem a
varredura seqencial de toda a tabela. Se for realmente necessria a utilizao do
operador lgico <>, utilize-o em um campo que no corresponda ao primeiro componente
do ndice utilizado. No nosso exemplo da tabela oper-ord, ele poderia ser aplicado para
qualquer campo menos o nr-ord-prod, sendo que quanto mais abaixo na estrutura do
ndice, melhor. Ou seja, a utilizao do operador lgico <> no campo op-codigo impacta
muito menos na performance do que a utilizao no campo it-codigo.

-RANGE MATCHES (<, >, <=, >=, BEGINS) seguem a mesma recomendao dada
para o operador lgico <>. Deve-se evitar utiliza-los nos primeiros componentes do ndice,
e NUNCA aplica-los ao primeiro campo do ndice, mesmo que para os demais campos
sejam utilizados EQUALITY MATCHES.

-EVITE a utilizao da funo MATCHES, que no faz aproveitamento dos ndices

-A ordem dos campos na clusula WHERE no importa, desde que a seqncia de
componentes do ndice seja mantida.

FOR EACH oper-ord
WHERE oper-ord.nr-ord-prod = i-nr-ord-prod
AND oper-ord.it-codigo = c-it-codigo
NO-LOCK:

Equivale a:

FOR EACH oper-ord
WHERE oper-ord.it-codigo = c-it-codico
AND oper-ord.nr-ord-prod = i-nr-ord-prod
NO-LOCK:

-Se for necessrio utilizar a clusula BY em um FOR EACH, procure sempre informar um
campo que seja o primeiro componente de um ndice.

-NUNCA utilize um IF...THEN...ELSE em uma clusula WHERE, sob pena de obrigar o
PROGRESS a realizar uma busca seqencial na tabela. Utilize variveis auxiliares para
receber um valor conforme a condio e realize a busca com essas variveis.

-Procure evitar ao mximo a utilizao do operador lgico OR em uma clusula WHERE.

Regras para seleo de ndices:

Se mltiplos ndices no podem ser selecionados, o PROGRESS segue as seguintes regras
para escolher um ndice:

1)Um ndice no utilizado (ou necessrio) se for fornecido um ROWID.
2)Se a opo USE-INDEX especificada, o PROGRESS utiliza o ndice informado.
3)Se a opo CONTAINS usada, ele seleciona o WORD-INDEX.
4)Se um ndice nico e todos os componentes desse ndice so comparados utilizando-se
EQUALITY MATCHES (=) e o outro ndice no-nico, o PROGRESS escolhe o ndice
nico.
5)O ndice com maior nmero de EQUALITY MATCHES (=).

Manual de Performance em Progress



6)O ndice com uma comparao BEGINS (porque BEGINS considerada como 2 RANGE
MATCHES)
7)O ndice com maior nmero de RANGE MATCHES
8)O ndice com o critrio de ordenao (BY). Isso acontece apenas se a clusula WHERE no
prover informaes suficientes para a seleo de outro ndice.
9)Pelo nome do ndice, em ordem alfabtica.
10)O ndice primrio.



DICAS DE PERFORMANCE

-NUNCA utilize as INCLUDES de traduo (ut-liter, ut-table, ut-field) dentro de loops. Sempre
que for necessria a utilizao de literais dentro de um loop ou de um FOR EACH, utilize
variveis para conter as literais e realize o ASSIGN dentro do loop com essas variveis.

Certo:

{utp/ut-liter.i Literal}
ASSIGN c-liter = return-value.
FOR EACH item NO-LOCK:
CREATE tt-item.
BUFFER-COPY item TO tt-item
ASSIGN tt-item.msg = c-liter.
END.

Errado:

FOR EACH item NO-LOCK:
CREATE tt-item.
{utp/ut-liter.i Literal}
BUFFER-COPY item TO tt-item
ASSIGN tt-item.msg = return-value.
END.

Isso degrada a performance porque dentro da INCLUDE ut-liter (e da ut-field e ut-table tambm),
existe uma chamada para um programa externo, que como j vimos, acaba degradando a performance.

-Procure tornar o programa mais inteligente. Por exemplo, em um programa que realiza vrias
atualizaes repetidas na tabela saldo-estoq, interessante armazenar o ROWID utilizado
da primeira vez e depois realizar a busca do saldo utilizando-se desse ROWID.

-Caso realmente no seja possvel a melhoria da performance do programa para os nveis
desejados pelo usurio, procure dar-lhe algum feed-back, ou seja, um retorno do que est
acontecendo durante o processo. Essa dica no aumenta realmente a performance do
programa, mas faz com que o tempo passe mais rpido para o usurio: muito mais
agradvel para ele esperar dois minutos de processamento e acompanhar o que est
sendo feito do que ficar dois longos minutos olhando para a ampulheta do windows.

-Procure utilizar o mximo de condies possveis no WHERE, mesmo que essas condies
no faam parte do ndice, desde que preferencialmente sejam EQUALITY-MATCHES,
ou seja, utilizem o operador lgico =, evitando o uso do NEXT.


Certo:

FOR EACH ord-prod
WHERE ord-prod.nr-ord-prod >= i-ord-ini
AND ord-prod.nr-ord-prod <= i-ord-fim
AND ord-prod.valorizada = no NO-LOCK:

Manual de Performance em Progress



DISP ord-prod.nr-ord-prod.
END.

Errado:

FOR EACH ord-prod
WHERE ord-prod.nr-ord-prod >= i-ord-ini
AND ord-prod.nr-ord-prod <= i-ord-fim
NO-LOCK:
IF ord-prod.valorizada THEN NEXT.
DISP ord-prod.nr-ord-prod.
END.

-NUNCA utilize funes na clusula WHERE nos campos da tabela sendo procurada. Utilize as
funes sempre nos valores a serem localizados.

Certo:

FOR EACH movto-estoq
WHERE movto-estoq.dt-trans = DATE (c-data) NO-LOCK:
END.

Errado:

FOR EACH movto-estoq
WHERE STRING (movto-estoq.dt-trans) = c-data NO-LOCK:
END.

O segundo FOR EACH ser executado de forma muito mais demorada, pois o
PROGRESS no pode saber o resultado da funo sem antes testa-la com todos os
registros. Ou seja, o PROGRESS ir realizar uma busca seqencial em toda a tabela.

-No utilize RAW-TRANSFER para passagem de parmetros. O comando RAW-TRANSFER
til apenas quando for necessria a compactao de todo um registro de uma tabela ou
TEMP-TABLE em um campo RAW. Em aplicaes normais, deve-se utilizar a passagem
de parmetros e TEMP-TABLES tradicional.

-Existem situaes, com SMART-QUERYS muito complexas, em que os programas do EMS
apresentam uma navegao extremamente lenta. Nesses casos, pode ser possvel a
quebra da QUERY original em duas ou mais QUERYS menores, com um link de
RECORD entre elas. Esse tipo de soluo no pode ser utilizada sempre, dependendo de
cada caso, mas pode auxiliar bastante na performance, pois diminui o nmero de JOINS na
QUERY e pode permitir a utilizao do parmetro INDEXED-REPOSITION.

-Quando um BROWSE tiver uma QUERY com vrias condies OR ou tiver condies que no
utilizam ndices, pode ser interessante transforma-lo em FREEFORM e utilizar um IF ou um
CASE para determinar qual o OPEN QUERY que ser utilizado. Esse cdigo colocado na
TRIGGER de OPEN-QUERY

IF l-nao-iniciadas AND
l-liberadas AND
l-alocadas AND
l-separadas AND
l-requisitadas AND
l-iniciadas AND
l-finalizadas AND
l-terminadas THEN
OPEN QUERY {&SELF-NAME}
FOR EACH tt-niveis NO-LOCK, ~
EACH ord-manut WHERE ord-manut.cd-tag = tt-niveis.cd-tag-pai
NO-LOCK BY ord-manut.dt-manut.

Manual de Performance em Progress



ELSE
OPEN QUERY {&SELF-NAME}
FOR EACH tt-niveis NO-LOCK, ~
EACH ord-manut WHERE ord-manut.cd-tag = tt-niveis.cd-tag-pai
AND (( ord-manut.estado = 1 AND l-nao-iniciadas ) or
( ord-manut.estado = 2 AND l-liberadas ) or
( ord-manut.estado = 3 AND l-alocadas ) or
( ord-manut.estado = 4 AND l-separadas ) or
( ord-manut.estado = 5 AND l-requisitadas ) or
( ord-manut.estado = 6 AND l-iniciadas ) or
( ord-manut.estado = 7 AND l-finalizadas ) or
( ord-manut.estado = 8 AND l-terminadas ) )
NO-LOCK BY ord-manut.dt-manut.

-Lembre-se que um programa deve ser rpido tambm no cliente, e no apenas durante o
desenvolvimento. Muitas vezes, a forma de utilizao ou a carga de trabalho a que o
programa submetido no cliente influencia bastante na performance do mesmo. Um fator
que costuma ter grande importncia em relao performance o travamento (lock) de
registros. Muitas vezes um programa bem rpido quando executado em ambiente de
desenvolvimento, mas torna-se bastante lento no cliente, por causa do travamento de
registros, quando existem dois ou mais usurios operando o mesmo programa
simultaneamente.
Procure travar os registros para atualizao durante o menor tempo possvel. Procure
tambm evitar que o programa pare devido a um registro travado, quando ele tem a
possibilidade de processar outros registros.
Deve-se entretanto, tomar alguns cuidados ao realizar a implementao acima, evitando a
ocorrncia de dead-locks. Um bom exemplo de cdigo inteligente, que evita ao mximo o
travamento de registros e a ocorrncia de dead-locks a API de gerao de movimento de
estoque CEP/CEAPI001.P, que incorpora, inclusive, o conceito de time-out para execuo
em RPC, evitando que um registro fique travado permanentemente.

Anda mungkin juga menyukai