PROBLEMA COM CRIAÇÃO DE BARRA DE PROGRESSO

JSGUERRA 30/10/2022 17:37:31
#500671
oi pessoal tudo bem?
será que poderiam me ajudar ?

Tenho a seguinte instrução Vb.net com execução de código SQL de consulta de 2 listas ListaMovimentos e ListaFunc e um Insert baseado na TSO.ExecuteSQL, como
o código sql da lista de movimento é extenso e está lendo uns milhares de registos para depois inserir outros tantos na tabela de movimentos, estava querendo colocar
uma barra de progresso para ter a noção do tempo demorado, já que essa execução demora mais de 20min!

já tentei adicionar uma barra de progresso tendo como referencia a variáveis "ì" ou "j" nas instruções While para executar o PerformStep() e invocar o Application.DoEvents() para um
Thread.Sleep(40) usando o MOD, mas sempre que coloco algo no seguimento das instruções While toda a execução do código fica impactada demorando a gerar o insert mais de 1h ?!?!?



.
.
.
...()

ListaMovimentos= DSO.Consulta("select distinct (trabalhadores...


While ListaMovimentos.NoFim = False

j = 1
ListaFunc = DSO.Consulta(";with AnosEfetivos as (...

i = 1

While ListaFunc.NoFim = False

campo1 = ListaFunc.x
campo2 = ListaFunc.y
campo3 = ListaFunc.z

TSO.ExecuteSQL ( INSERT INTO [dbo].[TBL_Movimentos] ( ColMov1, ColMov2 , ColMov3 ) Values ( " & " Campo1 & ", " & " Campo2 & "," & " Campo3 & ")" )

i += 1
ListaFunc.Seguinte()

End While

j += 1

ListaMovimentos.Seguinte()

End While

End Sub

KERPLUNK 30/10/2022 20:47:20
#500672
Tenho quase certeza que da pra fazer isso sem um loop, puramente com SQL
OCELOT 31/10/2022 10:18:56
#500673
Provavelmente voce pode otimizar isso, dependendo do banco de dados pode ter como fazer um BULK INSERT, ou pelo menos juntar vários INSERTS em uma só execução que deixaria isso muito mais rápido.

Fora isso a questão da barra de progresso deixar o processo mais lento é normal, o que voce precisa fazer é atualizar ela o mínimo o possível, se voce tiver por exemplo inserindo 100 mil registros e voce fizer a barra ir de 0 a 100 mil atualizando ela a cada registro inserido isso vai ficar muito lento, mas se em vez de atualizar ela a cada registro voce fizer por exemplo a barra ir de apenas 0 a 100, e a cada registro alterado voce calcular quantos porcento já foram, arredondando pra um número inteiro, e só alterar o valor da barra e chamar o DoEvents caso ele tenha mudado muito provavelmente não vai ter diferença nenhuma de performance.

Para voce ter uma ideia, em um programa nosso interno aqui que calcula umas estatísticas e gera alguns arquivos usando mais de 3 milhões de registros, quem o programou em console mesmo colocou pra mostrar a porcentagem processada a cada registro, levava cerca de 1 hora para processar tudo, eu falei que dava pra melhorar só mudando a questão de atualizar a porcentagem a cada registro, otimizei isso e também alguns outros detalhes pra diminuir o uso de memória evitando alocação, mas o que deu mais diferença foi não mostrar na tela a porcentagem a cada registro, caiu para 10 minutos a execução. E isso para console, que ninguém imagina que escrever um texto nele possa ser algo lento, mas quando voce faz isso 3 milhões de vezes faz diferença, o mesmo vale para interfaces gráficas só que daí é mais custoso ainda pro programa.

Em um outro caso, eu tenho um programa que compara e atualiza um banco de dados online com um local, o programa inicial levava mais de 1 hora para atualizar, boa parte estava na execução de inserts, updates e deletes, que eram feitos um a um, depois de mudar e otimizar para executar vários inserts e updates juntos na mesma SQL caiu para 2 minutos o tempo de execução dele, e a maior parte do tempo ainda é gasto para ler e comparar os dados, quando ele realmente atualiza o banco online está levando alguns segundos.
NETMANIA 31/10/2022 18:26:54
#500680
Qual o banco de dados que voce usa? Que a maioria tem recursos de carga massiva onde voce pode gerar uma saída CSV e depois ler esses dados. Vou dar dois exemplos:

Tenho uma rotina de ETL (airflow) onde eu pego os dados de um banco e gero um CSV e depois trato os dados e mando para o banco usando o comando Copy do Redshift/Postgress que mando uma média de 2 mil linhas em menos de 15 segundos.

Outra situação: tenho um ETL que fiz que pega os dados e prepara para dar carga no MySQL em um Raspberry 3 com MySQL usando recurso de carga massiva, com um arquivo de mais de 200 mil linhas, usando cartão de memória classe 10 (que é o mais rápido até o momento) leva nem uns 60 segundos.

Fazer insert para cada linha vai ser mais lento do que voce gerar a carga massiva para o banco. Se falar qual a sua base de dados posso ver qual o comando equivalente.
KERPLUNK 31/10/2022 20:13:24
#500681
Mais ou menos isso NETMANIA. Se reparar, o que ele está fazendo é inserindo numa tabela, resultados de seleção de outra. E isso pode ser feito com um comando apenas, que é nessa linha:

Insert Into Tabela (campo1, campo2, campo3) Select campoA, campoB, campoC From OutraTabela where bla bla bla
NETMANIA 03/11/2022 12:23:11
#500704
Citação:

:
Mais ou menos isso NETMANIA. Se reparar, o que ele está fazendo é inserindo numa tabela, resultados de seleção de outra. E isso pode ser feito com um comando apenas, que é nessa linha:


Insert Into Tabela (campo1, campo2, campo3) Select campoA, campoB, campoC From OutraTabela where bla bla bla



Vai ser mais rápido que gerar um arquivo e mandar para o banco como sugeri.
Faça seu login para responder