Stack Overflow em Português Asked by Jefferson Quesado on February 7, 2021
Nas linguagens descendentes de Clipper, existe um operador chamado de “operador de atribuição de alias. Por exemplo, eu posso pegar um campo de um result set
a partir desse operador (exemplo em ADVPL):
cSQL += " SELECT "
cSQL += " TOP 1 1 EXISTE "
cSQL += " FROM ( "
cSQL += cQuery
cSQL += " ) AS X "
cSql := changeQuery(cSQL)
DBUseArea(.T.,'TOPCONN',TCGENQRY(,,cSql),_cAlias,.F.,.T.)
// uso do alias-assignment
nRet := (_cAlias)->EXISTE
// uso do alias-assignment para um método
(_cAlias)->(dbCloseArea())
Porém, eu não faço a mínima ideia do que esteja acontecendo por debaixo dos panos. Minha aplicação tem muito o uso disso, então, se há algum tipo de execução sendo feita executada em runtime pela linguagem, esse processamento consumirá tempo que, de outra maneira, seria dedicado a fazer computações na minha aplicação.
Um outro exemplo, em que talvez haja algum abuso do operador:
dbSelectArea("ZX1")
ZX1->(dbSetOrder(1))
ZX1->(dbGoTop())
ZX1->(dbSeek(cChave))
While !(ZX1->(EOF())) .AND. cChave == ZX1->(ZX1_FILIAL + ZX1_COD)
aadd(aZX1Stuff, { ZX1->ZX1_TIPO, alltrim(ZX1->ZX1_CP_PRO), alltrim(ZX1->ZX1_CP_GEO), ZX1->ZX1_TAM })
ZX1->(dbSkip())
EndDo
ZX1->(dbCloseArea())
Então, minhas dúvidas são:
->
em Clipper ou derivados (como Harbour ou ADVPL) gera algum impacto mensurável na performance da aplicação?Vejamos:
usar/abusar do -> em Clipper ou derivados (como Harbour ou ADVPL) gera algum impacto mensurável na performance da aplicação?
Resposta:
Existe diferença de tempo, porém estamos falando de nanossegundos de diferença. Esta diferença somente vai representar algo perto de um segundo de diferença em um processamento que você faz mais de um milhão e meio de troca de alias.
se sim, como consigo mensurar esse tempo?
Resposta:
Como o tempo é muito curto, você precisa fazer um LOOP com muitas iterações, usando uma expressão aliasada sem custo de processamento. Por exemplo, verificar por EOF()
ou pedir o RECNO()
atual da tabela. Você pode pegar o tempo em segundos, com precisão de milésimos de segundo usando a função seconds()
e guardando seu retorno em uma variável antes de começar a processar, fazer um ou dois milhões de iterações usando a expressão aliasada, medir o tempo subtraindo o retorno da função seconds()
após o processamento da variável que guardou os seconds()
antes de processar. Depois, repetir o mesmo loop com marcação de tempo, porém chamando EOF()
e RECNO()
sem usar (cAlias)->(xxx)
Em um teste local, um loop de 10 milhões de iterações com expressão aliasada fez 1,5 milhões de iterações por segundo. Sem a expressão aliasada, e sem trocar o alias, subiu para 2,3 milhões de iterações por segundo. Porém, se dentro do loop eu colocar -- ao invés da expressão (cAlias)->(Eof())
, eu fizer um DbSelectArea(cAlias)
e então verificar por EOF()
, o desempenho cai pra 1,2 milhões de iterações por segundo. Isso significa que a diferença entre usar ou não expressão aliasada é de apenas 2.31e-7 segundos , ou 0.000000231 s.
se sim e se eu mensurar como um ponto válido de otimização, como poderia fazer para otimizar o seu uso?
Resposta:
A dica do Maniero é legal, se você têm mais de uma operação para fazer no mesmo alias, condense dentro da expressão aliasada. PORÉM, isso pode prejudicar a legibilidade do código -- e por causa de alguns nanossegundos de diferença. -- Eu particularmente acho que não vale a pena. Se no seu processo inteiro, que demora alguns minutos, você trocou de alias dois milhões de vezes, e isso consumiu um segundo, otimizar isso para 0,7 segundos não representa nada no tempo total.
Answered by siga0984 on February 7, 2021
Só uma correção: nas linguagens descendentes de dBase II :) As chamadas xBase. Clipper já é descendente.
Originalmente dBase II tinha uma linguagem muito simplificada com sintaxe que lembrava um pouco COBOL mas aplicado mais diretamente para algo que era um pouco novidade na época, o tal do banco de dados relacional. O acesso aos membros do banco de dados era feito por comandos imperativos simples.
No PC veio o dBase III com algumas coisas que começaram afastar ligeiramente disto porque a linguagem começou ter mais recursos de programação e começou ter uma sintaxe que lembrava um pouco Pascal ou C, mas era só algo bem pontual e novo.
Por performance e facilidade de distribuição alguém resolveu criar um compilador de dBase, o tal do Clipper. Com o tempo algumas features foram sendo adicionadas para ficar com mais cara de linguagem de programação, podendo até estender algumas coisas. Ali inventaram essa notação que parecia com um acesso a um objeto composto, como era a struct
do C, então você colocava o nome do objeto, o operador (se é que podemos chamar assim) que alguns dizem ser de contextualização e o membro que poderia ser um campo do da tabela do banco de dados ou uma função que age nele. Só funciona em tabelas e esse contexto é sempre em qual tabela a operação será feita.
A parte mais legal é que as pessoas poderiam parar de dar nomes para campos com prefixo usando o nome da tabela. No começo precisava porque você ficava sem contexto visual o que obviamente complicava a legibilidade. Permitindo, mas não obrigando, pôr o nome da tabela deixou de ser necessário dar nomes com notação húngara nos campos. O que foi um alívio porque os campos só podiam ter 10 caracteres no nome.
O Clipper 5 mudou tudo, eles resolveram romper com o dBase que estava afundando mesmo e se transformaram em uma linguagem de programação que por acaso acessava um banco de dados. Essa notação se fortaleceu e na verdade, apesar da sintaxe anterior funcionar através do excelente pré-processador da linguagem, Clipper 5 de verdade parecia mais com C (um um toque de BASIC) do que COBOL, e o uso dos prefixos se tornou o padrão.
Claro, a Totvs não entendeu isso e não tinha um padrão de usar o prefixo ou não mesmo na sua versão mais nova do ERP que foi 100% escrita em Clipper 5. Por isso ainda usam notação húngara. EU sugeri arrumar isso antes que se tornasse impraticável mudar, o que dá para imaginar como o ganho seria importante e ter 4 caracteres extras para expressar melhor nos nomes dos campos. Não aceitaram.
Quando surgiu a ADVPL continuaram do mesmo jeito, e de fato seria complicado mudar nessa altura (eu ainda tentaria mudar pelo menos as novidades, que não fica lindo, mas ajuda).
Não sei dizer se o Clipper Summer 87 tinha diferença de performance entre usar uma forma ou outra, mas provavelmente era igual ao Clipper 5 que tinha sim uma diferença irrisória, dessas que você mal consegue medir até em grandes volumes. Nunca medi no Harbour e em ADVPL menos ainda, mas é altamente provável, e pelo histórico pode até ter algum custo adicional, mas ainda irrelevante, você não deve se preocupar com isso. SE ADVPL ficar muito lento não me surpreenderá, mas duvido, será muito grave (bom tinha um bug em Clipper Summer 87 que o SKIP -1
) era dezenas ou centenas de vezes mais lento que o SKIP 1
, e a árvore permitia fazer ambos no mesmo tempo. Muita gente comprou a bomba do Joiner só por causa disso :)
Não sei métodos de medição de ADVPL exceto pegar o Time()
:)
Duvido que tenha uma forma de otimizar, e que valha a pena. De qualquer forma é quase certo que será otimização prematura, você não está precisando disto para seu código se tornar mais rápido. "Garanto" que se alguém mexer um tiquinho nessas funções internas conseguem dar um ganho maior, e ninguém quer fazer isto.
Por questões de legibilidade deveria esquecer que existe o tal do dbSelectArea()
ou SELECT
.
Claro, ele funciona melhor quando não se usa notação húngara. Como usam eu nem sei se deveria usar o prefixo (alguns casos não tem como não usar ou complica demais o código), ficaria mais legível por não ter redundância. Mas ainda prefiro o seu uso como padrão.
Não posso falar sobre a implementação do ADVPL mas em Harbour a função analisa o contexto que ela está e faz troca para o acesso interno, então simplificadamente é cair em um if
que troca um valor. O fato de existir essa possibilidade tudo já ficou mais lento, mesmo que não esteja usando esse prefixo, mas novamente de forma irrelevante. O compilador controla o estado do contexto de forma global, é feito mesmo.
Reforço que em uma linguagem basicamente de script que roda em uma VM (que para o ADVPL nem é otimizada) isso não faz nem cosquinha, vocês perde absurdamente mais por outras razões.
Acho "abusivo" usar os dois mecanismos de seleção da tabela, deveria escolher um ou outro.
Experimenta isto:
ZX1->(dbSetOrder(1), dbGoTop(), dbSeek(cChave))
Essa melhora é só por questão de legibilidade, não ter tanta redundância, não vai melhorar a performance. De qualquer forma esse dbGotTop()
não deveria fazer algum sentido, mas pode ser por algum problema de implementação do sistema de acesso à tabelas em SQL. Não sei se você percebeu você usa o métodos de acesso à tabelas DBF antigas do Clipper em uma espécie de cursor gerado pela query no banco de dados atravpes do SQL.
O meu DbSeek()
e outras funções tinha um parâmetro com a ordem do índice. Coloquei para todos usarem, praticamente ninguém usou, acho que acreditavam que escrever mais linhas dava a impressão de estarem sendo mais produtivos.
Até a pouco ainda podia usar só 10 caracteres em ADVPL. Algumas coisas agora (agora mesmo) podem usar mais caracteres, mas não sei se nomes de campos. Pelo menos em campos de tabela custom eu não usaria notação húngara, até para ajudar diferenciar.
Answered by Maniero on February 7, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP