|
DICA TÉCNICA:
Reread, Lock & companhia:
usar ou não usar em aplicações OOP? - parte 2
Na edição anterior do eUpdate, desmistificamos alguns mitos relativos à utilização dos comandos que acessam o buffer de registro: Reread, Lock, Saverecord, etc.
Vimos também uma situação onde a utilização destes comandos não é aconselhável.
Nesta segunda e última parte do artigo, veremos dois tópicos práticos. Primeiro, uma situação real do dia-a-dia onde a utilização destes comandos é preferível a utilizar os dicionários de dados.
Para terminar, mostraremos como você pode alterar seu código que faz uso destes comandos de forma a tornar a execução muito mais rápida em ambientes multi-usuário.
Um caso típico de utilização
Existem situações típicas onde os comandos de acesso ao buffer de registro são úteis. Por exemplo, suponha que devido a uma nova necessidade dos usuários, foi criado um campo (até então não existente) no arquivo de clientes: FL_ATIVO.
Você configurou este campo como Checkbox no dicionário de dados e os valores possíveis são “S” ou “N”.
Evidentemente, todos os registros existentes no momento ficarão inválidos, pois este campo estará em branco.
Você pode criar um programa de acerto sem nenhuma interface com o usuário que irá varrer toda a base de clientes e colocar o valor “N” para este campo.
Nesta situação, não há motivo para criar uma View dentro do sistema ou um programa usando os dicionários de dados, pois este processo será executado uma única vez e depois poderá ser descartado.
No Visual DataFlex 10.1, um programa deste tipo pode ser criado usando a opção Basic Application da caixa de diálogo Create New...:

Um programa de ajuste deste tipo teria a seguinte “cara”:

Uma pequena alteração: uma grande melhora
Como vimos, os comandos de acesso ao buffer de registro não são proibidos em aplicações OOP. Ao contrário, há situações onde eles são indicados em lugar de usar os DDOs.
Na maior parte das operações, entretanto, você pode ter um ganho significativo de performance se fizer uma pequena alteração no seu código fonte.
Por exemplo, suponha que, em um botão de uma View, você criou um código usando os comandos abaixo para varrer todos os títulos de um determinado cliente e acumular o total no campo Clientes.Tit_Aberto:
Procedure OnClick
// Varre todos os títulos em aberto do cliente posicionado
// e acumula o total no vampo Clientes.Tit_Aberto
Clear Clientes
Move (Current_Record(Clientes_DD(Self))) To Clientes.Recnum
Find Eq Clientes By Recnum
Clear Titulos
Move Clientes.Codigo To Titulos.Cod_Cliente
Find Ge Titulos By Index.2
While (Found And Titulos.Cod_Cliente = Clientes.Codigo)
If (Titulos.Status = “A”)) Begin // Apenas títulos abertos
Reread Clientes
Add Titulos.Valor To Clientes.Tit_Aberto
Saverecord Clientes
Unlock
End
Find Gt Titulos By Index.2
Loop
End_Procedure // OnClick
O maior problema deste processamento é o grande gargalo que o comando Reread pode se tornar no sistema.
Como vimos na edição anterior, o comando Reread não trava apenas os arquivos especificados em sua linha de comando, mas todos os que estiverem abertos em modo normal na aplicação. Entenda que por aplicação, estamos nos referindo ao programa principal (.SRC) e não à tela.
Sendo assim, se tivermos 1000 arquivos abertos no programa, estes 1000 arquivos serão travados a cada comando Reread executado. Há dois efeitos de degradação de performance neste caso:
1) O primeiro é para quem está executando este processamento, o qual será mais lento, pois tem que conseguir travar 1000 arquivos e não apenas 1. Pode haver um delay adicional se outro usuário estiver fazendo uma gravação ou exclusão em um destes 1000 arquivos.
2) O segundo efeito é para os outros usuários que estiverem trabalhando no sistema, que sentirão uma evidente lentidão ao tentar gravar ou excluir registros.
Como este código não faz uso de nenhuma validação do dicionário de dados, uma alternativa muito simples e que resultará em um ganho absurdo de performance é criar um objeto de dicionário de dados “limpo” apenas para este processamento. Veja o código alterado abaixo:
Object Clientes_BPO Is A DataDictionary
Set Main_File To Clientes.File_Number
End_Object
Procedure OnClick
// Varre todos os títulos em aberto do cliente posicionado
// e acumula o total no vampo Clientes.Tit_Aberto
Send Clear Of Clientes_BPO
Send Find_By_Recnum Of Clientes_BPO Clientes.File_Number ;
(Current_Record(Clientes_DD(Self)))
Clear Titulos
Move Clientes.Codigo To Titulos.Cod_Cliente
Find Ge Titulos By Index.2
While (Found And Titulos.Cod_Cliente = Clientes.Codigo)
If (Titulos.Status = “A”)) Begin // Apenas títulos abertos
Set Field_Changed_Value Of Clientes_BPO Field ;
Clientes.Tit_Aberto To (Clientes.Tit_Aberto + Titulos.Valor)
Send Request_Save Of Clientes_BPO
End
Find Gt Titulos By Index.2
Loop
End_Procedure // OnClick
A principal diferença que resulta em ganho de performance neste código é que o dicionário de dados não irá travar todos os arquivos abertos na aplicação, mas apenas aqueles que estão na estrutura de DDOs e que são afetados pelo processo de gravação. Como em nosso código foi criado um dicionário de dados “limpo” para o arquivo de Clientes, ele é o único que será travado.
Note também que esta alteração parte do pressuposto que não existe nenhum outro processamento dentro do sistema que atualiza este campo do arquivo de clientes, caso contrário teríamos que fazer o acúmulo do valor dentro da procedure Update do DDO.
Evidentemente há várias outras formas mais aconselháveis de executar este processamento, como usar um BusinessProcess, mas com a dica acima, você poderá obter um grande ganho de performance com uma pequena alteração e, quando tiver tempo, reveja este código para usar um BusinessProcess, ou melhor ainda, usar as procedures Update e Backout do dicionário de dados do arquivo de títulos para manter o campo sempre atualizado, dispensando a execução de um processamento para isso.
Veja também
Sugerimos que você consulte o seguinte item para mais informações sobre os conceitos abortados nesta parte do artigo:
• Artigo nº 1138 do Knowledge Base 4developers (acesso restrito aos assinantes do PSE):
Comandos de gravação deixam a aplicação OOP lenta
|