Segue um rascunho de boas praticas na manipulação de tabelas em processos.
Primeiro de tudo, é sempre bom colocar sempre manipulações de tabelas em transações como no exemplo a seguir:
DO ON STOP UNDO, LEAVE:
FIND FIRST <tablename> EXCLUSIVE-LOCK.
END.
Para ter uma maior controle em uma transação é possível criar uma transação customizada para manipular de acordo com possíveis falhas, se exemplo a seguir é criada uma transação denominada “Grava“.
Como a intenção é não interromper o processo, ao ocorrer um erro não dará a mensagem de erro, será chamada uma outra procedure “registraErro” que vai registrar o erro em arquivo ou mandar e-mail dependendo da necessidade.
Grava:
DO TRANS ON ERROR UNDO Grava, LEAVE Grava :
/*Vai buscar o registro dando pegando para manipular sem registrar qualquer erro */
FIND FIRST <tabela> EXCLUSIVE-LOCK NO-WAIT NO-ERROR.
/* Verifica se a tabela esta travada por outro usuário, se estiver saí da transação */
IF LOCKED(<tabela>) THEN DO:
registraErro("Tabela em uso").
UNDO Grava, LEAVE Grava.
END.
ASSIGN <tabela>.<campo> = <valor>.
/* Faz validação da integridade dos dados na tabela */
VALIDATE <tabela>.
/* Se tiver algum erro registrado, desfaz as alterações realizadas e saí da transação */
IF ERROR-STATUS:ERROR THEN DO:
registraErro(ERROR-STATUS:GET-MESSAGE[1]).
UNDO Grava, LEAVE Grava.
END.
/* Muito importante, executar um release para liberar a tabela,
(não dar o famoso erro de tabela em uso por fulano) */
RELEASE <tabela> NO-ERROR.
/* Mais uma verificação se existe algum erro na transação*/
CATCH eSysError AS Progress.Lang.SysError:
registraErro(eSysError:GetMessage(1)).
END CATCH.
END. /* Grava */
Outra dica boa é saber a forma correta de fazer a busca de uma tabela:
FIND FIRST: Um FIND FIRST vai direto no primeiro registro e a tabela passa a ficar disponível depois da busca más não é tão bom com múltiplos índices, recomentado em tabelas simples ou tabelas temporárias.
FIND FIRST <tabela> NO-LOCK NO-ERROR.
FOR FIRST: Também trás o primeiro registro que encontrar na tabela, a vantagem sobre o FIND FIRST é de poder usar ordenação de registro ORDER BY, assim o primeiro que encontrar pode ser mesmo o primeiro que o usuário busca.
Existem duas possibilidades de uso do FOR FIRST que ao alterar entre “:” ou “.” no final da condição muda o seu comportamento. Se usar dois pontos “:“, o transforme em uma transação e os registros existem dentro desta transação. Quando usa apenas ponto “.” ele se comporta como o FIND FIRST e o registro localizado existe após sua execução.
FOR FIRST é recomentado em tabelas maiores ou complexas onde podem ser aplicados diversos índices.
/* FOR FIRST como transação */
FOR FIRST <tabela> NO-LOCK:
<registro>
END.
/* FOR FIRST para usar o registro após sua execução */
FOR FIRST <tabela> NO_LOCK. END.
<registro>
FIND LAST/ FOR LAST: Mesma lógica do FIRST porém pegando o ultimo registro.
Melhorar desempenho na busca de registros em tabelas complexas
Para ter melhor desempenho ao buscar registros em tabelas com grande volume de registros procure nomear o índice que é melhor aplicado e use FIELDS para pegar apenas os campos que realmente serão usados, isso terá grande efeito no desempenho da busca:
FOR EACH <tabela> FIELDS (campo1, campo2, campo3) USE-INDEX <index>
WHERE <condição>
NO-LOCK:
<lógica>
END.
Esse é só um rascunho de programa, mais detalhes podem ser consultados nos links a baixo:
https://help.consultingwerkcloud.com/openedge/102b/langref-07-09.html
https://stackoverflow.com/questions/42543675/openedge-record-lock-debugging
https://knowledgebase.progress.com/articles/Article/000045865