 |
ActiveDelphi .: O site do programador Delphi! :.
|
| Exibir mensagem anterior :: Exibir próxima mensagem |
| Autor |
Mensagem |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
Enviada: Seg Ago 28, 2017 6:02 pm Assunto: Muito demorado para gravar na tabela com loop? |
|
|
Tenho 168.939 registro para inserir na tabela mais preciso verificar se existe o ID na tabela se existir faz um update se não insert
E este método deixa muito lento.
| Código: | function Tdm.VerificaSeTemID(const sNomeTable: String; iID: Integer): Boolean;
function GetNomeCampoPK(const sNomeTable: String): String;
begin
with qryAcoes do
begin
Close;
SQL.Clear;
SQL.Text := ' SELECT * FROM ' + sNomeTable;
Open;
Result := Fields[0].FieldName;
end;
end;
var
Fieled_Pk: String;
begin
Fieled_Pk := GetNomeCampoPK(sNomeTable);
with qryAcoes do
begin
Close;
SQL.Clear;
SQL.Text := ' SELECT * FROM ' + sNomeTable + ' WHERE ' + Fieled_Pk +
' = :pID ';
ParamByName('pID').AsInteger := iID;
// ShowMessage(SQL.Text);
Open;
if not IsEmpty then
Result := True // se for true então é update
else
Result := False; // se for false é insert
end;
end; |
Estes métodos ai faz a consulta se tem na tabela o ID
só que passo isso no loop todos as 168.939 vezes
| Código: | for j := 0 to Pred(Lista.Count) do
begin
if Trim(Lista[j]) = EmptyStr then
Continue;
Lista2.DelimitedText := Lista[j];
with dm.qryGrade do
begin
// retorna o id que vem da web
// se tiver ID na tabela então update, se não intere na tabela
if FListaTablesControls.GetVerificaSeTemID('grade',
StrToIntDef(Lista2[0], 0)) then
Edit
else
Append;
FieldByName('id_cadastro').AsInteger := StrToIntDef(Lista2[1], 0);
FieldByName('id_produto').AsInteger := StrToIntDef(Lista2[2], 0);
FieldByName('id_grade_atributo_valor').Value := Lista2[3];
FieldByName('id_usuario_alterou').Value := Lista2[4];
FieldByName('codigo_barra_pai').Value := Lista2[5];
FieldByName('codigo_barra').Value := Lista2[6];
FieldByName('codigo_interno').Value := Lista2[7];
FieldByName('qtd_atual').Value := Lista2[8];
FieldByName('qtd_minima').Value := Lista2[9];
FieldByName('qtd_locacao').Value := Lista2[10];
FieldByName('qtd_locacao_locado').Value := Lista2[11];
FieldByName('valor_custo').Value := Lista2[12];
FieldByName('valor_varejo_avista').Value := Lista2[13];
FieldByName('valor_varejo_aprazo').Value := Lista2[14];
FieldByName('valor_atacado_avista').Value := Lista2[15];
FieldByName('valor_atacado_aprazo').Value := Lista2[16];
FieldByName('ativo').Value := Lista2[17];
FieldByName('data_alteracao').AsDateTime :=
StrToDateTimeDef(Lista2[18], 0);
FieldByName('data_sincronismo').AsDateTime :=
StrToDateTimeDef(Lista2[19], 0);
FieldByName('id_web').AsInteger := StrToIntDef(Lista2[20], 0);
Post;
Gauge1.Progress := j + 1;
end;
Application.ProcessMessages;
end; |
Se eu desativo esta consulta ai fica rapido a consulta se não demora muito.
O que devo fazer para melhorar isso?
Obrigado. _________________ Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree |
|
| Voltar ao Topo |
|
 |
imex Moderador

Registrado: Sexta-Feira, 7 de Janeiro de 2011 Mensagens: 11666
|
Enviada: Seg Ago 28, 2017 8:49 pm Assunto: |
|
|
Boa noite,
Como aparentemente os dados retornados pela query da função GetNomeCampoPK não são utilizados, somente os nomes dos campos, sugiro que seja acrescentado um filtro para que não seja retornado nenhum registro do BD. Ex:
| Código: | | SQL.Text := ' SELECT * FROM ' + sNomeTable + ' WHERE 0 = 1'; |
E como a tabela é sempre a mesma no looping, acho que essa função poderia ser executada somente uma vez antes de começar o looping.
Espero que ajude
Editado pela última vez por imex em Qui Set 28, 2023 11:38 am, num total de 1 vez |
|
| Voltar ao Topo |
|
 |
wjuniordias Profissional


Registrado: Sexta-Feira, 16 de Março de 2012 Mensagens: 667
|
Enviada: Ter Ago 29, 2017 8:09 am Assunto: Re: Muito demorado para gravar na tabela com loop? |
|
|
Já tentou usar o comando "insert or update"?
Em relação ao loop, o arrayDML resolveria o problema da lentidão, fiz alguns testes em alguns projetos aqui na empresa e tive uma performance considerável.
http://www.clipatecinformatica.com.br/2017/08/comando-array-dml-firedac-no-delphi.html _________________ "O sábio nunca diz tudo o que pensa, mas pensa sempre tudo o que diz." (Aristóteles) |
|
| Voltar ao Topo |
|
 |
leo_cj Colaborador

Registrado: Sábado, 26 de Março de 2011 Mensagens: 1335
|
Enviada: Ter Ago 29, 2017 9:46 am Assunto: |
|
|
Se o problema for essas verificações, o que você pode fazer é o seguinte:
- Criar uma tabela temporária com as mesmas colunas da tabela desejada.
- Incluir as informações da lista nessa tabela temporária
feito isso, você realiza um update com select e um insert com select ex:
Supondo que minha tabela seja Cliente
| Citação: | ID_Cliente Integer Identity(1,1),
NM_Cliente Varchar(20),
NR_Celular Varchar(18) |
criaria então a tabela temporária com a mesma estrutura, mas com o campo ID_Cliente apenas como Integer, sem o auto incremento (identity)
uma vez com todos os registros na temporária vamos as instruções de inclusão e update
| Código: | UPDATE Cli
SET
Cli.NM_Cliente = CT.NM_Cliente,
Cli.NR_Cliente = CT.NR_Cliente
FROM
Cliente AS Cli
INNER JOIN ClienteTMP AS CT
ON Cli.ID_Cliente = CT.ID_Cliente |
Nesse update, pegamos apenas as informações da tabela temporária que existem na tabela principal.
| Código: | INSERT INTO Cliente (NM_Cliente, NR_Celular)
SELECT NM_Cliente,
NR_Celular
FROM ClienteTMP CT
WHERE NOT EXISTS(SELECT 1
FROM Cliente
WHERE ID_Cliente = CT.ID_Cliente) |
Nesse insert, verificamos os códigos que estão na tabela temporária mas não existem na tabela principal. |
|
| Voltar ao Topo |
|
 |
natanbh1 Colaborador

Registrado: Terça-Feira, 15 de Março de 2011 Mensagens: 3093 Localização: Belo Horizonte - MG
|
Enviada: Ter Ago 29, 2017 10:11 am Assunto: |
|
|
Uma alternativa seria testar o Locate ao invés do seu método para verificar existe o item para ver se melhora a performance.
Outra sugestão é, se for manter o seu método, ao invés de buscar todos os campos, busque somente os campos necessários.
Troque:
| Código: | | SQL.Text := ' SELECT * FROM ' + sNomeTable; |
Por:
| Código: | | SQL.Text := ' SELECT Campo1 FROM ' + sNomeTable; // somente os campos necessários |
_________________ ''A persistência é o caminho para o êxito.''
Charlie Chaplin |
|
| Voltar ao Topo |
|
 |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
Enviada: Ter Ago 29, 2017 11:53 am Assunto: |
|
|
| imex escreveu: | Boa noite,
Como aparentemente os dados retornados pela query da função GetNomeCampoPK não são utilizados, somente os nomes dos campos, sugiro que seja acrescentado um filtro para que não seja retornado nenhum registro do BD. Ex:
| Código: | | SQL.Text := ' SELECT * FROM ' + sNomeTable + ' WHERE 0 = 1'; |
E como a tabela é sempre a mesma no looping, acho que essa função poderia ser executada somente uma vez antes de começar o looping.
Espero que ajude |
Ja arrumei e mesmo assim o tempo é longo 1 hora e 14 minutos
Meu problema é na verificação que tenho que fazer a cada looping se insere ou edita o campo
arrayDML (gostei desta ideia)
Mais não deu certo na hora de gravar no banco
| Código: | procedure TfrmConfiguracoes.BtnDownloadClick(Sender: TObject);
var
Lista, Lista2: TStringList;
j, l: Integer;
DS: TDataSource;
FListaTablesControls: TListaTablesControls;
Grid: TDBGrid;
sSQLInsert, sSQLUpdate: String;
iNumInserts: Integer;
begin
FListaTablesControls := TListaTablesControls.Create;
try
lblCronometro.Caption := FormatDateTime('ss.zzz', fTempo);
sSQLInsert := ' INSERT INTO grade( ' +
' id_cadastro, id_produto, id_grade_atributo_valor, id_usuario_alterou, '
+ ' codigo_barra_pai, codigo_barra, codigo_interno, qtd_atual, qtd_minima, '
+ ' qtd_locacao, qtd_locacao_locado, valor_custo, valor_varejo_avista, '
+ ' valor_varejo_aprazo, valor_atacado_avista, valor_atacado_aprazo, ' +
' porc_varejo_avista, porc_varejo_aprazo, porc_atacado_avista, ' +
' porc_atacado_aprazo, ativo, ' +
' data_alteracao, data_sincronismo, id_web' + ' VALUES ( ' +
' :Pid_cadastro, :Pid_produto, :Pid_grade_atributo_valor, :Pid_usuario_alterou, '
+ ' :Pcodigo_barra_pai, :Pcodigo_barra, :Pcodigo_interno, :Pqtd_atual, :Pqtd_minima, '
+ ' :Pqtd_locacao, :Pqtd_locacao_locado, :Pvalor_custo, :Pvalor_varejo_avista, '
+ ' :Pvalor_varejo_aprazo, :Pvalor_atacado_avista, :Pvalor_atacado_aprazo, '
+ ' :Pporc_varejo_avista, :Pporc_varejo_aprazo, :Pporc_atacado_avista, '
+ ' :Pporc_atacado_aprazo, :Pativo, ' +
' :Pdata_alteracao, :Pdata_sincronismo, :Pid_web ';
sSQLUpdate := ' UPDATE grade ' +
' SET id_cadastro = :Pid_cadastro, id_produto = :Pid_produto, ' +
' id_grade_atributo_valor = :id_grade_atributo_valor, ' +
' id_usuario_alterou = :Pid_usuario_alterou, codigo_barra_pai = :Pcodigo_barra_pai, '
+ ' codigo_barra = :Pcodigo_barra, codigo_interno = :Pcodigo_interno, '
+ ' qtd_atual = :Pqtd_atual, qtd_minima = :Pqtd_minima, ' +
' qtd_locacao = :Pqtd_locacao, qtd_locacao_locado = :Pqtd_locacao_locado, '
+ ' valor_custo = :Pvalor_custo, valor_varejo_avista = :Pvalor_varejo_avista, '
+ ' valor_varejo_aprazo = :Pvalor_varejo_aprazo, ' +
' valor_atacado_avista = :Pvalor_atacado_avista, valor_atacado_aprazo = :Pvalor_atacado_aprazo, '
+ ' porc_varejo_avista = :Pporc_varejo_avista, ' +
' porc_varejo_aprazo = :Pporc_varejo_aprazo, porc_atacado_avista = :Pporc_atacado_avista, '
+ ' porc_atacado_aprazo = :Pporc_atacado_aprazo, ' +
' ativo = :Pativo, data_alteracao = :Pdata_alteracao, ' +
' data_sincronismo = :Pdata_sincronismo, id_web = :Pid_web ' +
' WHERE id_web = :Pid_web ';
Lista := TStringList.Create;
Lista2 := TStringList.Create;
try
Lista.LoadFromFile('grade.csv', TEncoding.UTF8);
Lista2.StrictDelimiter := True;
Lista2.Delimiter := ';'; // aqui defino qual separador
Gauge1.MaxValue := Lista.Count;
// iniciar cronometro
fMomento := GetTickCount;
crono.Enabled := True;
Lista.BeginUpdate;
if dm.qryGrade.Active then
dm.qryGrade.Close;
dm.qryGrade.SQL.Add(sSQLInsert);
iNumInserts := Lista.Count;
dm.qryGrade.Params.ArraySize := iNumInserts;
dm.qryGrade.DisableControls;
for j := 0 to Pred(Lista.Count) do
begin
if Trim(Lista[j]) = EmptyStr then
Continue;
Lista2.DelimitedText := Lista[j];
with dm.qryGrade do
begin
// retorna o id que vem da web
// se tiver ID na tabela então update, se não intere na tabela
// ShowMessage(Lista2[20]);
// if FListaTablesControls.GetVerificaSeTemID('grade',
// StrToIntDef(Lista2[20], 0)) then
// SQL.Add(sSQLUpdate)
// else
// SQL.Add(sSQLInsert);
ParamByName('Pid_cadastro').AsInteger := StrToIntDef(Lista2[1], 0);
ParamByName('Pid_produto').AsInteger := StrToIntDef(Lista2[2], 0);
ParamByName('Pid_grade_atributo_valor').AsString := Lista2[3];
ParamByName('Pid_usuario_alterou').AsInteger := StrToIntDef(Lista2[4], 0);
ParamByName('Pcodigo_barra_pai').asString := Lista2[5];
ParamByName('Pcodigo_barra').asString := Lista2[6];
ParamByName('Pcodigo_interno').asString := Lista2[7];
ParamByName('Pqtd_atual').AsFloat := StrToFloatDef(Lista2[8], 0);
ParamByName('Pqtd_minima').AsFloat := StrToFloatDef(Lista2[9], 0);
ParamByName('Pqtd_locacao').AsFloat := StrToFloatDef(Lista2[10], 0);
ParamByName('Pqtd_locacao_locado').AsFloat := StrToFloatDef(Lista2[11], 0);
ParamByName('Pvalor_custo').AsCurrency := StrToCurrDef(Lista2[12], 0);
ParamByName('Pvalor_varejo_avista').AsCurrency := StrToCurrDef(Lista2[13], 0);
ParamByName('Pvalor_varejo_aprazo').AsCurrency := StrToCurrDef(Lista2[14], 0);
ParamByName('Pvalor_atacado_avista').AsCurrency := StrToCurrDef(Lista2[15],0);
ParamByName('Pvalor_atacado_aprazo').AsCurrency := StrToCurrDef(Lista2[16],0);
ParamByName('Pporc_varejo_avista').AsFloat := StrToFloatDef(Lista2[17],0);
ParamByName('Pporc_varejo_aprazo').AsFloat := StrToFloatDef(Lista2[18],0);
ParamByName('Pporc_atacado_avista').AsFloat := StrToFloatDef(Lista2[19],0);
ParamByName('Pporc_atacado_aprazo').AsFloat := StrToFloatDef(Lista2[20],0);
ParamByName('Pativo').AsString := Lista2[21];
ParamByName('Pdata_alteracao').AsDateTime :=
StrToDateTimeDef(Lista2[22], 0);
ParamByName('Pdata_sincronismo').AsDateTime :=
StrToDateTimeDef(Lista2[23], 0);
ParamByName('Pid_web').AsInteger := StrToIntDef(Lista2[24], 0);
Gauge1.Progress := j + 1;
end;
Application.ProcessMessages;
end;
if iNumInserts > 0 then
dm.qryGrade.Execute(iNumInserts, 0);
dm.qryGrade.Active := false;
finally
Lista.EndUpdate;
dm.qryGrade.EnableControls;
FreeAndNil(Lista);
FreeAndNil(Lista2);
lblTotQtd.Caption := FormatFloat('#,0',
Grid.DataSource.DataSet.RecordCount);
// parar cronometro
crono.Enabled := false;
// desaloca da memoria
FreeAndNil(Grid);
end;
finally
FreeAndNil(FListaTablesControls);
end;
end; |
Ao executar da o erro
---------------------------
Debugger Exception Notification
---------------------------
Project WCSync.exe raised exception class EPgNativeException with message '[FireDAC][Phys][PG][libpq] ERROR: syntax error at or near "VALUES"'.
---------------------------
Break Continue Help
---------------------------
Alias queria saber se é possível fazer o update e insert juntos no código. _________________ Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree |
|
| Voltar ao Topo |
|
 |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
Enviada: Ter Ago 29, 2017 11:59 am Assunto: |
|
|
| natanbh1 escreveu: | Uma alternativa seria testar o Locate ao invés do seu método para verificar existe o item para ver se melhora a performance.
Outra sugestão é, se for manter o seu método, ao invés de buscar todos os campos, busque somente os campos necessários.
Troque:
| Código: | | SQL.Text := ' SELECT * FROM ' + sNomeTable; |
Por:
| Código: | | SQL.Text := ' SELECT Campo1 FROM ' + sNomeTable; // somente os campos necessários |
|
Ja troquei, continua lento para grande volume de dados
Eu recebo um arquivo csv para gravar na base de dados. _________________ Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree |
|
| Voltar ao Topo |
|
 |
imex Moderador

Registrado: Sexta-Feira, 7 de Janeiro de 2011 Mensagens: 11666
|
Enviada: Ter Ago 29, 2017 12:10 pm Assunto: |
|
|
Qual banco de dados (e versão) você está utilizando?
Acho que talvez seja possível eliminar essa parte do código se o banco que você está utilizando tiver um comando como o Merge ou semelhante. |
|
| Voltar ao Topo |
|
 |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
|
| Voltar ao Topo |
|
 |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
Enviada: Ter Ago 29, 2017 1:11 pm Assunto: |
|
|
| leo_cj escreveu: | Se o problema for essas verificações, o que você pode fazer é o seguinte:
- Criar uma tabela temporária com as mesmas colunas da tabela desejada.
- Incluir as informações da lista nessa tabela temporária
feito isso, você realiza um update com select e um insert com select ex:
Supondo que minha tabela seja Cliente
| Citação: | ID_Cliente Integer Identity(1,1),
NM_Cliente Varchar(20),
NR_Celular Varchar(1 |
criaria então a tabela temporária com a mesma estrutura, mas com o campo ID_Cliente apenas como Integer, sem o auto incremento (identity)
uma vez com todos os registros na temporária vamos as instruções de inclusão e update
| Código: | UPDATE Cli
SET
Cli.NM_Cliente = CT.NM_Cliente,
Cli.NR_Cliente = CT.NR_Cliente
FROM
Cliente AS Cli
INNER JOIN ClienteTMP AS CT
ON Cli.ID_Cliente = CT.ID_Cliente |
Nesse update, pegamos apenas as informações da tabela temporária que existem na tabela principal.
| Código: | INSERT INTO Cliente (NM_Cliente, NR_Celular)
SELECT NM_Cliente,
NR_Celular
FROM ClienteTMP CT
WHERE NOT EXISTS(SELECT 1
FROM Cliente
WHERE ID_Cliente = CT.ID_Cliente) |
Nesse insert, verificamos os códigos que estão na tabela temporária mas não existem na tabela principal. | Se eu não conseguir com a ideia do array vou ver esta Leo. _________________ Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree |
|
| Voltar ao Topo |
|
 |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
Enviada: Ter Ago 29, 2017 2:02 pm Assunto: |
|
|
| adriano_servitec escreveu: | | imex escreveu: | Qual banco de dados (e versão) você está utilizando?
Acho que talvez seja possível eliminar essa parte do código se o banco que você está utilizando tiver um comando como o Merge ou semelhante. | Postgres 9.6.4 |
Vamos la Imex,
Preciso verificar o seguinte
Se o arquivo que esta vindo a ultima linha a onde tem o ID que vem do arquivo for igual ao campo id_web(tela local) e a data de alteracao que vem do arquivo for maior que a data de sincronismo da tabela local então é um update se não um insert e se nenhuma das condições for então significa que ambos estao iguais no arquivo e na tabela.
Da pra fazer com merge no postgres? _________________ Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree |
|
| Voltar ao Topo |
|
 |
strak2012 Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014 Mensagens: 1518 Localização: Maceió - AL
|
Enviada: Ter Ago 29, 2017 2:35 pm Assunto: |
|
|
Consultar para inserir ou atualizar via programação num loop é algo muito demorado e inviável.
Das melhores solução mencionada estão:
1ª - Verificar se há suporte para o comando insert or update a ação de atualizar ou inserir fica com o SGDB em questão, isso vai diminuir em metade o tempo gasto
2ª - Trabalhar com comando Array DML fantástico e eficiente, pois muitas operações pode ser executada de uma unica vez, isso há uma ganho de performance sem igual.
Se não há possibilidade para a 1ª então recomenda que seja criado procedure stored, que faça o papel de verificar e inserir ou atualizar quando houver o tal registro desta forma voce passa o papel de verificar e atualizar ou inserir para o SGDB em questão.
Ainda não coloquei em pratica os comando Array DML apenas dei uma lida por alto, só será valido se estiver a usar componentes com suporte para tal, mais é uma baita solução.
bom é isso boa sorte. _________________ Tudo podemos quando tudo sabemos! |
|
| Voltar ao Topo |
|
 |
imex Moderador

Registrado: Sexta-Feira, 7 de Janeiro de 2011 Mensagens: 11666
|
Enviada: Ter Ago 29, 2017 3:04 pm Assunto: |
|
|
| adriano_servitec escreveu: | | Se o arquivo que esta vindo a ultima linha a onde tem o ID que vem do arquivo for igual ao campo id_web(tela local) e a data de alteracao que vem do arquivo for maior que a data de sincronismo da tabela local então é um update se não um insert e se nenhuma das condições for então significa que ambos estao iguais no arquivo e na tabela. |
Pelo que entendi acho que essa verificação pode ser feita só uma vez na aplicação logo no início para ver se o looping deve ser executado ou não.
| adriano_servitec escreveu: | | Da pra fazer com merge no postgres? |
Pelo que vi o Postgre tem o comando Merge. Com o Merge (ou o Insert or Update em outros bancos como o Firebird) é possível especificar algumas condições para ver se deve ser executado um Insert ou um Update. Segue abaixo um exemplo onde é verificado se o campo id_web passado por parâmetro existe ou não para executar um Update ou um Insert respectivamente:
| Código: | MERGE INTO Grade g
USING (VALUES(:Pid_web as id_web,
:Pid_cadastro as id_cadastro,
:Pid_produto as id_produto,
:Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web
WHEN NOT MATCHED
INSERT (id_web, id_cadastro, id_produto, id_grade_atributo_valor)
VALUES(v.id_web, v.id_cadastro, v.id_produto, v.id_grade_atributo_valor)
WHEN MATCHED
UPDATE SET
id_cadastro = v.id_cadastro,
id_produto = v.id_produto,
id_grade_atributo_valor = v.id_grade_atributo_valor; |
Espero que ajude |
|
| Voltar ao Topo |
|
 |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
Enviada: Ter Ago 29, 2017 3:07 pm Assunto: |
|
|
| strak2012 escreveu: | Consultar para inserir ou atualizar via programação num loop é algo muito demorado e inviável.
Das melhores solução mencionada estão:
1ª - Verificar se há suporte para o comando insert or update a ação de atualizar ou inserir fica com o SGDB em questão, isso vai diminuir em metade o tempo gasto
2ª - Trabalhar com comando Array DML fantástico e eficiente, pois muitas operações pode ser executada de uma unica vez, isso há uma ganho de performance sem igual.
Se não há possibilidade para a 1ª então recomenda que seja criado procedure stored, que faça o papel de verificar e inserir ou atualizar quando houver o tal registro desta forma voce passa o papel de verificar e atualizar ou inserir para o SGDB em questão.
Ainda não coloquei em pratica os comando Array DML apenas dei uma lida por alto, só será valido se estiver a usar componentes com suporte para tal, mais é uma baita solução.
bom é isso boa sorte. | Obrigado pela dica amigo. _________________ Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree |
|
| Voltar ao Topo |
|
 |
adriano_servitec Colaborador

Registrado: Sexta-Feira, 30 de Janeiro de 2004 Mensagens: 17618
|
Enviada: Ter Ago 29, 2017 3:08 pm Assunto: |
|
|
| imex escreveu: | | adriano_servitec escreveu: | | Se o arquivo que esta vindo a ultima linha a onde tem o ID que vem do arquivo for igual ao campo id_web(tela local) e a data de alteracao que vem do arquivo for maior que a data de sincronismo da tabela local então é um update se não um insert e se nenhuma das condições for então significa que ambos estao iguais no arquivo e na tabela. |
Pelo que entendi acho que essa verificação pode ser feita só uma vez na aplicação logo no início para ver se o looping deve ser executado ou não.
| adriano_servitec escreveu: | | Da pra fazer com merge no postgres? |
Pelo que vi o Postgre tem o comando Merge. Com o Merge (ou o Insert or Update em outros bancos como o Firebird) é possível especificar algumas condições para ver se deve ser executado um Insert ou um Update. Segue abaixo um exemplo onde é verificado se o campo id_web passado por parâmetro existe ou não para executar um Update ou um Insert respectivamente:
| Código: | MERGE INTO Grade g
USING (VALUES(:Pid_web as id_web,
:Pid_cadastro as id_cadastro,
:Pid_produto as id_produto,
:Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web
WHEN NOT MATCHED
INSERT (id_web, id_cadastro, id_produto, id_grade_atributo_valor)
VALUES(v.id_web, v.id_cadastro, v.id_produto, v.id_grade_atributo_valor)
WHEN MATCHED
UPDATE SET
id_cadastro = v.id_cadastro,
id_produto = v.id_produto,
id_grade_atributo_valor = v.id_grade_atributo_valor; |
Espero que ajude |
São 160 mil registros vindo do csv que preciso gravar. Por isso preciso verificar uma a um pra ver se tem na tabela (eu acho)
Se não como implemento este codigo acima passado?
Olha como é o arquivo que vem
| Citação: | ;62065;2067393;;39621;1609004933634;1609004933634;;1.000;0.000;0.000;0.000;95.20;0.00;238.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680795
;62065;2067460;;39621;1609004933638;1609004933638;;2.000;0.000;0.000;0.000;95.20;0.00;238.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680796
;62065;2067345;;39621;1708023033740;1708023033740;;2.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680797
;62065;2067339;;39621;1708023033738;1708023033738;;2.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680798
;62065;2067332;;39621;1708023033736;1708023033736;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680799
;62065;2067300;;39621;1708023233640;1708023233640;;2.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680800
;62065;2067282;;39621;170105957342;170105957342;;2.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680801
;62065;2067325;;39621;1708023233644;1708023233644;;0.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680802
;62065;2067288;;39621;170105957344;170105957344;;1.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680803
;62065;2067359;;39621;1608035833534;1608035833534;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680804
;62065;2067295;;39621;1708023233638;1708023233638;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680805
;62065;2067279;;39621;170105957338;170105957338;;0.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680806
;62065;2067466;;39621;1609004933640;1609004933640;;1.000;0.000;0.000;0.000;95.20;0.00;238.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680807
;62065;2067349;;39621;1708023033742;1708023033742;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680808
;62065;2067362;;39621;1608035833536;1608035833536;;0.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680809
;62065;2067276;;39621;170105957340;170105957340;;2.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680810
;62065;2067380;;39621;1608035833542;1608035833542;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680811 |
Isso é um pequeno parte de 160 mil reg.
Também não entendi este MERGE como é feito
Minha tabela tem esta estrutura
| Código: | CREATE TABLE public.grade
(
id_grade integer NOT NULL DEFAULT nextval('grade_id_grade_seq'::regclass),
id_cadastro integer NOT NULL,
id_produto integer NOT NULL,
id_grade_atributo_valor character varying(255) DEFAULT NULL::character varying,
id_usuario_alterou integer,
codigo_barra_pai character(20) NOT NULL,
codigo_barra character(20) DEFAULT NULL::bpchar,
codigo_interno character(20) DEFAULT NULL::bpchar,
qtd_atual numeric(10,3) DEFAULT 0.000,
qtd_minima numeric(10,3) DEFAULT 0.000,
qtd_locacao numeric(10,3) DEFAULT 0.000,
qtd_locacao_locado numeric(10,3) DEFAULT 0.000,
valor_custo numeric(10,2) DEFAULT NULL::numeric,
valor_varejo_avista numeric(10,2) DEFAULT NULL::numeric,
valor_varejo_aprazo numeric(10,2) DEFAULT NULL::numeric,
valor_atacado_avista numeric(10,2) DEFAULT NULL::numeric,
valor_atacado_aprazo numeric(10,2) DEFAULT NULL::numeric,
porc_varejo_avista numeric(18,15) DEFAULT NULL::numeric,
porc_varejo_aprazo numeric(30,20) DEFAULT NULL::numeric,
porc_atacado_avista numeric(18,15) DEFAULT NULL::numeric,
porc_atacado_aprazo numeric(18,15) DEFAULT NULL::numeric,
ativo smallint DEFAULT '1'::smallint,
alt_estoque character(1),
editar character(1),
excluir character(1),
id_web integer,
data_alteracao timestamp with time zone,
data_sincronismo timestamp with time zone,
CONSTRAINT grade_pkey PRIMARY KEY (id_grade)
) |
Não entendi esta parte
| Código: | USING (VALUES(:Pid_web as id_web,
:Pid_cadastro as id_cadastro,
:Pid_produto as id_produto,
:Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web |
Outra coisa
Via código no delphi uso um fdQuery (firedac) neste codigo
| Código: | MERGE INTO Grade g
USING (VALUES(:Pid_web as id_web,
:Pid_cadastro as id_cadastro,
:Pid_produto as id_produto,
:Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web
WHEN NOT MATCHED
INSERT (id_web, id_cadastro, id_produto, id_grade_atributo_valor)
VALUES(v.id_web, v.id_cadastro, v.id_produto, v.id_grade_atributo_valor)
WHEN MATCHED
UPDATE SET
id_cadastro = v.id_cadastro,
id_produto = v.id_produto,
id_grade_atributo_valor = v.id_grade_atributo_valor; |
Passo os parametros via parambyname e um execute no final? Isso dentro do loop que le o csv? _________________ Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Editado pela última vez por adriano_servitec em Ter Ago 29, 2017 3:25 pm, num total de 1 vez |
|
| Voltar ao Topo |
|
 |
|
|
Enviar Mensagens Novas: Proibido. Responder Tópicos Proibido Editar Mensagens: Proibido. Excluir Mensagens: Proibido. Votar em Enquetes: Proibido.
|
|