Pular para o conteúdo principal

Postagem em destaque

BlackTDN :: LeetCode :: Comparando Implementações Harbour e TLPP para o Desafio Longest Palindromic Substring

_Créditos das imagens: ChatGPT_ ### LeetCode :: Comparando Implementações Harbour e TLPP para o Desafio Longest Palindromic Substring Resolver o problema do [Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/description/) é um exercício clássico de programação, que desafia desenvolvedores a encontrar a maior substring palindrômica dentro de uma string. Recentemente, exploramos soluções tanto em Harbour quanto em TLPP (Total Language Protheus Programming). Neste artigo, comparamos as implementações nessas duas linguagens, destacando suas semelhanças, diferenças e funcionalidades específicas. #### Implementações em Harbour ##### Versão 5.1 Essa solução utiliza a técnica de expansão a partir do centro do palíndromo. Cada caractere ou par de caracteres consecutivos é considerado um possível "centro". O algoritmo expande em ambas as direções enquanto os caracteres forem iguais, retornando o maior palíndromo encontrado. ##### Versão 5....

BlackTDN :: cArqTab :: Otimizando a Abertura do Sistema: Como a Escolha do Método de Carregamento Afeta o Desempenho

_Créditos da imagem: Gerada com auxílio do ChatGPT_

# cArqTab :: Como o carregamento de informações em uma variável pode tornar lenta a abertura do sistema TOTVS Microsiga Protheus

---

# Comparando LoadFromDBQuery e LoadFromDBWhile: Vantagens e Desempenho

No desenvolvimento de soluções para o TOTVS Microsiga Protheus, otimizar o tempo de execução das funções é essencial, especialmente quando lidamos com grandes volumes de dados. Neste artigo, vamos analisar a diferença de desempenho entre os métodos `LoadFromDBQuery` e `LoadFromDBWhile`, utilizando os tempos de execução para demonstrar a vantagem de cada abordagem.

## Contexto do Teste

Para avaliar o desempenho, executamos dois procedimentos distintos:

- **U_TSTArqTabLoadDBQuery**: utiliza a função `LoadFromDBQuery`.
- **U_TSTArqTabLoadDBWhile**: utiliza a função `LoadFromDBWhile`.

Os comandos foram executados no ambiente Cygwin, e PowerShell e os tempos foram medidos da seguinte forma:

*Cygwin
```bash
$ time C:/totvs/tst/smartclient/smartclient.exe -q -p=U_TSTArqTabLoadDBQuery -a=01:01 -c=LOCALHOST -e=USERFUNCTION -m -l

real    0m7,253s
user    0m0,000s
sys     0m0,015s

$ time C:/totvs/tst/smartclient/smartclient.exe -q -p=U_TSTArqTabLoadDBWhile -a=01:01 -c=LOCALHOST -e=USERFUNCTION -m -l

real    0m35,420s
user    0m0,015s
sys     0m0,015s
```

### Diferença de Tempo

- **`LoadFromDBQuery`**: Tempo de execução total: aproximadamente 7 segundos.
- **`LoadFromDBWhile`**: Tempo de execução total: aproximadamente 35 segundos.


*PowerShell
```bash

Measure-Command { Start-Process -FilePath "C:\totvs\tst\smartclient\smartclient.exe" -ArgumentList "-q", "-p=U_TSTArqTabLoadDBQuery", "-a=01:01", "-c=LOCALHOST", "-e=USERFUNCTION", "-m", "-l" -Wait }

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 7
Milliseconds      : 91
Ticks             : 70919283
TotalDays         : 8,20825034722222E-05
TotalHours        : 0,00196998008333333
TotalMinutes      : 0,118198805
TotalSeconds      : 7,0919283
TotalMilliseconds : 7091,9283

Measure-Command { Start-Process -FilePath "C:\totvs\tst\smartclient\smartclient.exe" -ArgumentList "-q", "-p=U_TSTArqTabLoadDBWhile", "-a=01:01", "-c=LOCALHOST", "-e=USERFUNCTION", "-m", "-l" -Wait }

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 18
Milliseconds      : 33
Ticks             : 180330167
TotalDays         : 0,000208715471064815
TotalHours        : 0,00500917130555556
TotalMinutes      : 0,300550278333333
TotalSeconds      : 18,0330167
TotalMilliseconds : 18033,0167

```

### Diferença de Tempo

- **`LoadFromDBQuery`**: Tempo de execução total: aproximadamente 8 segundos.
- **`LoadFromDBWhile`**: Tempo de execução total: aproximadamente 18 segundos.

A diferença é significativa: `LoadFromDBQuery` é cerca de 2 a 5 vezes mais rápido do que `LoadFromDBWhile`.

## Análise das Funções

### LoadFromDBQuery

A função `LoadFromDBQuery` executa uma consulta diretamente no banco de dados utilizando SQL. Esse método aproveita os recursos de agregação de strings e de filtros diretamente no banco de dados, o que reduz a necessidade de processar dados linha a linha no lado do cliente.

#### Vantagens:

- **Desempenho**: Executa a lógica de forma mais eficiente diretamente no banco de dados, reduzindo o número de interações entre o cliente e o servidor.
- **Menor Uso de Recursos**: A agregação de resultados no banco de dados minimiza a carga de processamento do lado cliente.
- **Facilidade de Manutenção**: O código SQL pode ser adaptado conforme a necessidade, facilitando ajustes de performance e leitura de dados.

### LoadFromDBWhile

A função `LoadFromDBWhile` faz a leitura dos registros utilizando um loop `while` para percorrer cada linha da tabela `SX2` e montar a string `cArqTab`.

#### Desvantagens:

- **Desempenho Inferior**: O loop `while` processa os registros linha por linha, o que é significativamente mais lento, especialmente em tabelas grandes.
- **Maior Consumo de Recursos**: Por ser um processo iterativo e dependente do lado do cliente, consome mais tempo de CPU e memória.
- **Manutenção**: Códigos iterativos tendem a ser mais complexos e difíceis de ajustar para otimização.

## Conclusão

O uso de `LoadFromDBQuery` traz uma vantagem clara em termos de desempenho para cenários onde a leitura e a agregação de dados podem ser realizadas diretamente no banco de dados. A execução é mais rápida, eficiente e consome menos recursos do lado cliente, sendo ideal para ambientes que necessitam de alta performance e grande volume de dados.

Por outro lado, o `LoadFromDBWhile` pode ser considerado em situações onde a lógica de agregação é muito específica e difícil de implementar diretamente em SQL, mas, para a maioria dos casos, a abordagem com `LoadFromDBQuery` será mais vantajosa.

O impacto da escolha entre essas duas abordagens é visível na diferença de tempo apresentada: **7 segundos contra 35 segundos** em um exemplo simples. Para sistemas em produção, essa diferença pode representar um ganho de performance significativo, melhorando a experiência do usuário final e a eficiência operacional.

---

*TLPP
```xBase
#include "totvs.ch"
#include "dbinfo.ch"
#include "tbiconn.ch"
#include "parmtype.ch"

#define __EMPFIL__ "01:01"

/*
    Powershell:
    Measure-Command { Start-Process -FilePath "C:\totvs\tst\smartclient\smartclient.exe" -ArgumentList "-q", "-p=U_TSTArqTabLoadDBQuery", "-a=01:01", "-c=LOCALHOST", "-e=USERFUNCTION", "-m", "-l" -Wait }
    Measure-Command { Start-Process -FilePath "C:\totvs\tst\smartclient\smartclient.exe" -ArgumentList "-q", "-p=U_TSTArqTabLoadDBWhile", "-a=01:01", "-c=LOCALHOST", "-e=USERFUNCTION", "-m", "-l" -Wait }

    CYGWin:
    time C:/totvs/tst/smartclient/smartclient.exe -q -p=U_TSTArqTabLoadDBQuery -a=01:01 -c=LOCALHOST -e=USERFUNCTION -m -l
    time C:/totvs/tst/smartclient/smartclient.exe -q -p=U_TSTArqTabLoadDBWhile -a=01:01 -c=LOCALHOST -e=USERFUNCTION -m -l
*/

procedure U_TSTArqTabLoadDBQuery(cEmpFil)
    local aEmpFil as array
    local cEmp,cFil as character
    local cArqTab:="" as character
    DEFAULT cEmpFil:=__EMPFIL__
    aEmpFil:=StrTokArr(cEmpFil,":")
    cEmp:=aEmpFil[1]
    cFil:=aEmpFil[2]
    PREPARE ENVIRONMENT EMPRESA (cEmp) FILIAL (cFil)
        cArqTab:=TSTArqTabLoad():LoadFromDBQuery(cArqTab)
        if (FWMakeDir("c:\tmp\"))
            MemoWrite("c:\tmp\"+ProcName()+".log",cArqTab)
        endif
    RESET ENVIRONMENT
    FWFreeArray(@aEmpFil)
return

procedure U_TSTArqTabLoadDBWhile(cEmpFil)
    local aEmpFil as array
    local cEmp,cFil as character
    local cArqTab:="" as character
    DEFAULT cEmpFil:=__EMPFIL__
    aEmpFil:=StrTokArr(cEmpFil,":")
    cEmp:=aEmpFil[1]
    cFil:=aEmpFil[2]
    PREPARE ENVIRONMENT EMPRESA (cEmp) FILIAL (cFil)
        cArqTab:=TSTArqTabLoad():LoadFromDBWhile(cArqTab)
        if (FWMakeDir("c:\tmp\"))
            MemoWrite("c:\tmp\"+ProcName()+".log",cArqTab)
        endif
    RESET ENVIRONMENT
    FWFreeArray(@aEmpFil)
return

class TSTArqTabLoad
    static method LoadFromDBQuery(cArqTab as character) as character
    static method LoadFromDBWhile(cArqTab as character) as character
end class

static method LoadFromDBQuery(cArqTab) class TSTArqTabLoad
    local cTCGetDB:=Upper(TCGetDB()) as character
    local cSX2AliasTmp:=getNextAlias() as character
    local cSX2TableName as character
    paramtype 1 var cArqTab as character optional default ""
    cSX2TableName:=SX2->(dbInfo(DBI_FULLPATH))
    cSX2TableName:="%"+cSX2TableName+"%"
    if ("MSSQL"$cTCGetDB)
        beginSQL alias cSX2AliasTmp
            SELECT STRING_AGG(CAST(CONCAT(SX2.X2_CHAVE,SX2.X2_MODO,'/') AS VARCHAR(MAX)),'') AS X2_MODO
                FROM %exp:cSX2TableName% SX2
                WHERE SX2.%notDel%
                AND SX2.X2_CHAVE<>''
        endSQL
        cArqTab:=strTran((cSX2AliasTmp)->X2_MODO," ","")
        (cSX2AliasTmp)->(dbCloseArea())
        dbSelectArea("SX2")
    elseif ("POSTGRES"$cTCGetDB)
        beginSQL alias cSX2AliasTmp
            SELECT STRING_AGG(CONCAT(SX2.X2_CHAVE,SX2.X2_MODO,'/'),'') AS X2_MODO
                FROM %exp:cSX2TableName% SX2
                WHERE SX2.%notDel%
                AND SX2.X2_CHAVE<>''
        endSQL
        cArqTab:=strTran((cSX2AliasTmp)->X2_MODO," ","")
        (cSX2AliasTmp)->(dbCloseArea())
        dbSelectArea("SX2")
    elseif ("ORACLE"$cTCGetDB)
        beginSQL alias cSX2AliasTmp
            SELECT LISTAGG(SX2.X2_CHAVE||SX2.X2_MODO||'/','') WITHIN GROUP (ORDER BY SX2.X2_CHAVE) ON OVERFLOW TRUNCATE '.../' AS X2_MODO
                FROM %exp:cSX2TableName% SX2
                WHERE SX2.%notDel%
                AND SX2.X2_CHAVE<>''
        endSQL
        cArqTab:=strTran((cSX2AliasTmp)->X2_MODO," ","")
        (cSX2AliasTmp)->(dbCloseArea())
        dbSelectArea("SX2")
    endif
    if (empty(cArqTab).or.(".../"$cArqTab))
        cArqTab:=TSTArqTabLoad():LoadFromDBWhile(cArqTab)
    endif

return(cArqTab)

static method LoadFromDBWhile(cArqTab) class TSTArqTabLoad
    local aAreaSX2:=SX2->(FWGetArea()) as array
    paramtype 1 var cArqTab as character optional default ""
    if (empty(cArqTab).or.(".../"$cArqTab))
        SX2->(dbGotop())
        while (SX2->(!eof()))
            cX2Modo:=(SX2->(X2_CHAVE+X2_MODO))
            if (!(cX2Modo$cArqTab))
                cArqTab+=cX2Modo+"/"
            endif
            SX2->(dbSkip())
        end while
    endif
    FWRestArea(@aAreaSX2)
    FWFreeArray(@aAreaSX2)
return(cArqTab)
```

---

Comentários

Postagens mais visitadas