Looping em grande volume de dados
Pessoal,
Eu criei um programa em delphi (delphi 2007) onde uso os componentes IBX (IBQuery) e o banco de dados firebird 2.1 que tem o objetivo de transferir dados de um banco de dados firbird para outro banco de dados firebird.
Por exemplo tenho o BANCO1.fdb de onde preciso tranferir registros de determinadas tabelas para o BANCO2.fdb e apagar os resgistros transferidos do BANCO1.fdb.
Porem estou com perda de desempenho durante o looping que transfere os registros de um banco para o outro.
Se a minha aplicação começa migrando 400 registro/segundo no final termina com 25 registros/segundo. Estou falando em questão de aproximandamente 15.000.000 de registros.
Porem o BANCO2.FDB que é o desitno, não possui indices, nem trigger nas tabelas muito menos PK, isso já foi feito assim para que não houvesse perda de desempenho ao alimentar índices que causaria uma perda exponecial de velocidade.
Bom, creio que o problema não seja com o banco pois estou commitando os registro pelo menos a cada 500 no banco destino e origem.
O mais engraçado que acontece é que eu tenho várias tabelas a serem exportadas se a primeira tabela terminar á velocidade de 100 regsitros/segundo a proxima começa nessa mesma velocidade, porem isso somente teria lógica se quando eu fechar a abrir o sistema o importação das outras tabelas continuassem com a mesma velocidade de término, no entanto quando fecho e abro o sistema a velocidade volta à rapidez inicial (400 reg/seg) usando o mesmo BANCO2.fdb.
Alguem pode me ajudar dando algumas dicas de como posso evitar essa perda de desempenho no looping? Talves a forma que esteja fazendo está errada. Mas não consegui fazer de outra meneira por enquanto.
Obs.:
* todas as IBquerys utilizadas estão como unidirecionais.
* não estou usando IBUpateSQL e sim commando inserts e deletes executados através de IBQuerys
Obrigado.
Eu criei um programa em delphi (delphi 2007) onde uso os componentes IBX (IBQuery) e o banco de dados firebird 2.1 que tem o objetivo de transferir dados de um banco de dados firbird para outro banco de dados firebird.
Por exemplo tenho o BANCO1.fdb de onde preciso tranferir registros de determinadas tabelas para o BANCO2.fdb e apagar os resgistros transferidos do BANCO1.fdb.
Porem estou com perda de desempenho durante o looping que transfere os registros de um banco para o outro.
Se a minha aplicação começa migrando 400 registro/segundo no final termina com 25 registros/segundo. Estou falando em questão de aproximandamente 15.000.000 de registros.
Porem o BANCO2.FDB que é o desitno, não possui indices, nem trigger nas tabelas muito menos PK, isso já foi feito assim para que não houvesse perda de desempenho ao alimentar índices que causaria uma perda exponecial de velocidade.
Bom, creio que o problema não seja com o banco pois estou commitando os registro pelo menos a cada 500 no banco destino e origem.
O mais engraçado que acontece é que eu tenho várias tabelas a serem exportadas se a primeira tabela terminar á velocidade de 100 regsitros/segundo a proxima começa nessa mesma velocidade, porem isso somente teria lógica se quando eu fechar a abrir o sistema o importação das outras tabelas continuassem com a mesma velocidade de término, no entanto quando fecho e abro o sistema a velocidade volta à rapidez inicial (400 reg/seg) usando o mesmo BANCO2.fdb.
Alguem pode me ajudar dando algumas dicas de como posso evitar essa perda de desempenho no looping? Talves a forma que esteja fazendo está errada. Mas não consegui fazer de outra meneira por enquanto.
Obs.:
* todas as IBquerys utilizadas estão como unidirecionais.
* não estou usando IBUpateSQL e sim commando inserts e deletes executados através de IBQuerys
Obrigado.
Command Informatica
Curtidas 0
Respostas
Wilson Junior
17/11/2010
Verifique:
- se alguns objetos que você esteja criando está sendo liberados da memória (FreeAndNil);
- se algumas consultas estão sendo abertas, utilizadas e FECHADAS.
Espero ter colaborado.
- se alguns objetos que você esteja criando está sendo liberados da memória (FreeAndNil);
- se algumas consultas estão sendo abertas, utilizadas e FECHADAS.
Espero ter colaborado.
GOSTEI 0
Command Informatica
17/11/2010
Olá Paulista.
Obrigado pelas dicas, porem mesmo liberando todos os objetos que crio o desempenho continua caindo muito. Todas as querys que utilizo eu fecho no final (IBquery1.close).
Eu creio que tenha alguma coisa haver com o fetch dos registros que vão ocupando a memória, porem já monitorei a memória do computador quando o sistema está em execução e não está se elevando tando para ocorrer perda de desempenho, pois está ficando sempre abaixo da quantidade de memória física que possuo.
Mas muito obrigado.
Se alguem mais tiver como ajudar. Ficarei grato.
Obrigado pelas dicas, porem mesmo liberando todos os objetos que crio o desempenho continua caindo muito. Todas as querys que utilizo eu fecho no final (IBquery1.close).
Eu creio que tenha alguma coisa haver com o fetch dos registros que vão ocupando a memória, porem já monitorei a memória do computador quando o sistema está em execução e não está se elevando tando para ocorrer perda de desempenho, pois está ficando sempre abaixo da quantidade de memória física que possuo.
Mas muito obrigado.
Se alguem mais tiver como ajudar. Ficarei grato.
GOSTEI 0
Wilson Junior
17/11/2010
Tente utilizar transações para uma certa quantidade de registros (500 como você citou), talvez possa melhorar.
Espero ter colaborado.
Espero ter colaborado.
GOSTEI 0
Wilson Junior
17/11/2010
Como você está fazendo estes seus loops???
GOSTEI 0
Command Informatica
17/11/2010
Tente utilizar transações para uma certa quantidade de registros (500 como você citou), talvez possa melhorar.
Espero ter colaborado.
Espero ter colaborado.
Obrigado mais uma vez Paulista, porem não consegui enterder o que você quis dizer acima.
estou postando uma parte do código para você ver. Creio que ficará mais fácil assim.
Agradeço desde já.
procedure TdmArquivoMorto.procArquivarLogs(d_ArquivarAte: TDateTime);
var
// sera usada para copiar as informações do log corrente para a base do arquivo morto
qCopia :TIBQuery;
// sera usada para apagar o log corrente
qDelete :TIBQuery;
// copia o log corrente para a base do arquivo morto
procedure procCopiaLog;
var i :Integer;
campo :TField;
begin
qCopia.Close;
qCopia.SQL.Text :=
' INSERT INTO AUX006 ( '+
' LOG_USUARIO, LOG_SISTEMA, LOG_PROGRAMA, '+
' LOG_DATA, LOG_HORA, LOG_TIPO, '+
' LOG_HISTORICO, PRG_DESCRICAO, LOG_ID) '+
' VALUES( '+
' :LOG_USUARIO, :LOG_SISTEMA, :LOG_PROGRAMA, '+
' :LOG_DATA, :LOG_HORA, :LOG_TIPO, '+
' :LOG_HISTORICO, :PRG_DESCRICAO, :LOG_ID) ';
for i := 0 to qCopia.Params.Count - 1 do
begin
campo := qArquivarLogs.FindField(qCopia.Params[i].Name);
if campo <> nil then
qCopia.Params[i].Value := campo.Value;
end;
qCopia.ExecSQL;
end;
// Apaga o log corrente do cperfect
procedure procApagaLog;
var i :Integer;
begin
qDelete.Close;
qDelete.SQL.Text := ' DELETE FROM AUX006 '+
' WHERE LOG_ID = :LOG_ID ';
qDelete.ParamByName('LOG_ID').AsInteger := qArquivarLogs.FieldByName('LOG_ID').AsInteger;
qDelete.ExecSQL;
end;
begin
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Iniciando arquivamento de Logs (AUX006)');
qDelete := nil;
qCopia := nil;
//A função criar query dinamica criar uma instância de uma TIBQuery para o banco e transação especificados
qDelete := CriarQueryDinamica(dmBanco.Banco, Self.TBDCPerfect);
qCopia := CriarQueryDinamica(Self.BDArquivoMorto, Self.TBDArquivoMorto);
try
...
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Selecionando logs...');
// qArquivarLogs é unidirecional
qArquivarLogs.Close;
qArquivarLogs.SQL.Text :=
' SELECT AUX006.*, SIS003.PRG_DESCRICAO FROM AUX006 '+
' INNER JOIN SIS003 ON LOG_SISTEMA = PRG_SISTEMA '+
' AND LOG_PROGRAMA = PRG_PROGRAMA '+
' WHERE LOG_DATA <= :D_ARQUIVAR_ATE ';
qArquivarLogs.ParamByName('D_ARQUIVAR_ATE').AsDateTime := d_ArquivarAte;
qArquivarLogs.Open;
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Logs selecionados');
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Iniciando arquivamento de logs...');
while not qArquivarLogs.Eof do
begin
...
try
procCopiaLog();
procApagaLog();
//Realiza um commit a cada 500
procGravaAlteracoes();
except
on E :Exception do
begin
//realiza um rollback
procDesfazerAlteracoes();
LogProcesso(TLOGP_ERRO,'ARQUIVAR_LOGS',e.Message,dmArquivoMorto.qArquivarLogs);
end;
end;
qArquivarLogs.Next;
end;
//Grava o que estiver pendente
try
if Self.TBDArquivoMorto.InTransaction then
Self.TBDArquivoMorto.Commit;
if Self.TBDCPerfect.InTransaction then
Self.TBDCPerfect.Commit;
except
on e :Exception do
begin
procDesfazerAlteracoes();
LogProcesso(TLOGP_ERRO,'ARQUIVAR_LOGS',e.Message,qArquivarRecados);
end;
end;
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Arquivamento de logs concluído');
finally
qArquivarLogs.Close;
qCopia.Close;
qDelete.Close;
Self.Conectado := false;
if qDelete <> nil then
FreeAndNil(qDelete);
if qCopia <> nil then
FreeAndNil(qCopia);
end;
end;
GOSTEI 0
Command Informatica
17/11/2010
Então ninguém tem alguma dica para ajudar?
Agradeço desde já
Agradeço desde já
GOSTEI 0
Emerson Nascimento
17/11/2010
trabalhe com um numero limitado de registros por vez.
outra coisa: mapeie os campos para que não seja necessário efetuar um scan na lista de campos a cada cópia de registro.
procedure TdmArquivoMorto.procArquivarLogs(d_ArquivarAte: TDateTime);
var
// sera usada para copiar as informações do log corrente para a base do arquivo morto
qCopia :TIBQuery;
// sera usada para apagar o log corrente
qDelete :TIBQuery;
aParams: array of integer; // array com o mapeamento dos parâmetros
nFieldID: integer; // indice do campo chave para evitar a busca com FieldByName
lMsgAtiva: boolean;
// copia o log corrente para a base do arquivo morto
procedure procCopiaLog;
var i :Integer;
campo :TField;
begin
qCopia.Close;
qCopia.SQL.Text :=
' INSERT INTO AUX006 ( '+
' LOG_USUARIO, LOG_SISTEMA, LOG_PROGRAMA, '+
' LOG_DATA, LOG_HORA, LOG_TIPO, '+
' LOG_HISTORICO, PRG_DESCRICAO, LOG_ID) '+
' VALUES( '+
' :LOG_USUARIO, :LOG_SISTEMA, :LOG_PROGRAMA, '+
' :LOG_DATA, :LOG_HORA, :LOG_TIPO, '+
' :LOG_HISTORICO, :PRG_DESCRICAO, :LOG_ID) ';
// mapeia os parametros (apenas 1 vez) para evitar o scan
// efetuado pelo FindField e pelo FieldByName
if Length(aParams) = 0 then
begin
SetLength(aParams, qCopia.Params.Count);
nFieldID := qArquivarLogs.FieldByName('LOG_ID').Index;
for i := 0 to High(aParams) do
begin
campo := qArquivarLogs.FindField(qCopia.Params[i].Name);
if campo <> nil then
aParams[i] := campo.index;
else
aParams[i] := -1;
end;
end;
for i := 0 to High(aParams) do
if aParams[i] > -1 then
qCopia.Params[i].Value := qArquivarLogs.Fields[aParams[i]].Value;
qCopia.ExecSQL;
end;
// Apaga o log corrente do cperfect
procedure procApagaLog;
var i :Integer;
begin
qDelete.Close;
qDelete.SQL.Text := ' DELETE FROM AUX006 '+
' WHERE LOG_ID = :LOG_ID ';
qDelete.ParamByName('LOG_ID').AsInteger := qArquivarLogs.Fields[nFieldID].AsInteger;
qDelete.ExecSQL;
end;
begin
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Iniciando arquivamento de Logs (AUX006)');
qDelete := nil;
qCopia := nil;
lMsgAtiva := False;
//A função criar query dinamica criar uma instância de uma TIBQuery
//para o banco e transação especificados
qDelete := CriarQueryDinamica(dmBanco.Banco, Self.TBDCPerfect);
qCopia := CriarQueryDinamica(Self.BDArquivoMorto, Self.TBDArquivoMorto);
try
...
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Selecionando logs...');
SetLength(aParams, 0); // zera o array com o mapeamento dos parâmetros
while .t.
// qArquivarLogs é unidirecional
qArquivarLogs.Close;
qArquivarLogs.SQL.Text :=
' SELECT FIRST 5000 AUX006.*, SIS003.PRG_DESCRICAO FROM AUX006 '+ // seleciona 5000 registros
' INNER JOIN SIS003 ON LOG_SISTEMA = PRG_SISTEMA '+
' AND LOG_PROGRAMA = PRG_PROGRAMA '+
' WHERE LOG_DATA <= :D_ARQUIVAR_ATE ';
qArquivarLogs.ParamByName('D_ARQUIVAR_ATE').AsDateTime := d_ArquivarAte;
qArquivarLogs.Open;
if qArquivarLogs.IsEmpty then
break;
if not lMsgAtiva then
begin
lMsgAtiva := True;
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Logs selecionados');
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Iniciando arquivamento de logs...');
end;
// faz a gravacao de 5000 (cinco mil) registros por vez
// para evitar o acumulo de registros na memoria
while not qArquivarLogs.Eof do
begin
...
try
procCopiaLog();
procApagaLog();
//Realiza um commit a cada 500
procGravaAlteracoes();
except
on E :Exception do
begin
//realiza um rollback
procDesfazerAlteracoes();
LogProcesso(TLOGP_ERRO,'ARQUIVAR_LOGS',e.Message,dmArquivoMorto.qArquivarLogs);
end;
end;
qArquivarLogs.Next;
end;
// Grava o que estiver pendente
try
if Self.TBDArquivoMorto.InTransaction then
Self.TBDArquivoMorto.Commit;
if Self.TBDCPerfect.InTransaction then
Self.TBDCPerfect.Commit;
except
on e :Exception do
begin
procDesfazerAlteracoes();
LogProcesso(TLOGP_ERRO,'ARQUIVAR_LOGS',e.Message,qArquivarRecados);
end;
end;
end;
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Arquivamento de logs concluído');
finally
qArquivarLogs.Close;
qCopia.Close;
qDelete.Close;
Self.Conectado := false;
if qDelete <> nil then
FreeAndNil(qDelete);
if qCopia <> nil then
FreeAndNil(qCopia);
end;
end;
verifique se isso vai dar certo.
fiz todas as alterações no bloco de notas, pois estou sem o Delphi nesta máquina, então nem sei se a sintaxe está correta.
optei por 5.000 registros por vez. talvez a performance ainda seja boa selecionando 10.000 ou 15.000. faça os testes e veja se esta alteração surte algum efeito e se aumentar o número de registros ainda o torna satisfatório.
outra coisa: mapeie os campos para que não seja necessário efetuar um scan na lista de campos a cada cópia de registro.
procedure TdmArquivoMorto.procArquivarLogs(d_ArquivarAte: TDateTime);
var
// sera usada para copiar as informações do log corrente para a base do arquivo morto
qCopia :TIBQuery;
// sera usada para apagar o log corrente
qDelete :TIBQuery;
aParams: array of integer; // array com o mapeamento dos parâmetros
nFieldID: integer; // indice do campo chave para evitar a busca com FieldByName
lMsgAtiva: boolean;
// copia o log corrente para a base do arquivo morto
procedure procCopiaLog;
var i :Integer;
campo :TField;
begin
qCopia.Close;
qCopia.SQL.Text :=
' INSERT INTO AUX006 ( '+
' LOG_USUARIO, LOG_SISTEMA, LOG_PROGRAMA, '+
' LOG_DATA, LOG_HORA, LOG_TIPO, '+
' LOG_HISTORICO, PRG_DESCRICAO, LOG_ID) '+
' VALUES( '+
' :LOG_USUARIO, :LOG_SISTEMA, :LOG_PROGRAMA, '+
' :LOG_DATA, :LOG_HORA, :LOG_TIPO, '+
' :LOG_HISTORICO, :PRG_DESCRICAO, :LOG_ID) ';
// mapeia os parametros (apenas 1 vez) para evitar o scan
// efetuado pelo FindField e pelo FieldByName
if Length(aParams) = 0 then
begin
SetLength(aParams, qCopia.Params.Count);
nFieldID := qArquivarLogs.FieldByName('LOG_ID').Index;
for i := 0 to High(aParams) do
begin
campo := qArquivarLogs.FindField(qCopia.Params[i].Name);
if campo <> nil then
aParams[i] := campo.index;
else
aParams[i] := -1;
end;
end;
for i := 0 to High(aParams) do
if aParams[i] > -1 then
qCopia.Params[i].Value := qArquivarLogs.Fields[aParams[i]].Value;
qCopia.ExecSQL;
end;
// Apaga o log corrente do cperfect
procedure procApagaLog;
var i :Integer;
begin
qDelete.Close;
qDelete.SQL.Text := ' DELETE FROM AUX006 '+
' WHERE LOG_ID = :LOG_ID ';
qDelete.ParamByName('LOG_ID').AsInteger := qArquivarLogs.Fields[nFieldID].AsInteger;
qDelete.ExecSQL;
end;
begin
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Iniciando arquivamento de Logs (AUX006)');
qDelete := nil;
qCopia := nil;
lMsgAtiva := False;
//A função criar query dinamica criar uma instância de uma TIBQuery
//para o banco e transação especificados
qDelete := CriarQueryDinamica(dmBanco.Banco, Self.TBDCPerfect);
qCopia := CriarQueryDinamica(Self.BDArquivoMorto, Self.TBDArquivoMorto);
try
...
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Selecionando logs...');
SetLength(aParams, 0); // zera o array com o mapeamento dos parâmetros
while .t.
// qArquivarLogs é unidirecional
qArquivarLogs.Close;
qArquivarLogs.SQL.Text :=
' SELECT FIRST 5000 AUX006.*, SIS003.PRG_DESCRICAO FROM AUX006 '+ // seleciona 5000 registros
' INNER JOIN SIS003 ON LOG_SISTEMA = PRG_SISTEMA '+
' AND LOG_PROGRAMA = PRG_PROGRAMA '+
' WHERE LOG_DATA <= :D_ARQUIVAR_ATE ';
qArquivarLogs.ParamByName('D_ARQUIVAR_ATE').AsDateTime := d_ArquivarAte;
qArquivarLogs.Open;
if qArquivarLogs.IsEmpty then
break;
if not lMsgAtiva then
begin
lMsgAtiva := True;
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Logs selecionados');
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Iniciando arquivamento de logs...');
end;
// faz a gravacao de 5000 (cinco mil) registros por vez
// para evitar o acumulo de registros na memoria
while not qArquivarLogs.Eof do
begin
...
try
procCopiaLog();
procApagaLog();
//Realiza um commit a cada 500
procGravaAlteracoes();
except
on E :Exception do
begin
//realiza um rollback
procDesfazerAlteracoes();
LogProcesso(TLOGP_ERRO,'ARQUIVAR_LOGS',e.Message,dmArquivoMorto.qArquivarLogs);
end;
end;
qArquivarLogs.Next;
end;
// Grava o que estiver pendente
try
if Self.TBDArquivoMorto.InTransaction then
Self.TBDArquivoMorto.Commit;
if Self.TBDCPerfect.InTransaction then
Self.TBDCPerfect.Commit;
except
on e :Exception do
begin
procDesfazerAlteracoes();
LogProcesso(TLOGP_ERRO,'ARQUIVAR_LOGS',e.Message,qArquivarRecados);
end;
end;
end;
LogProcesso(TLOGP_INFORMACAO,'INFO_GERAL_ARQUIVAMENTO','Arquivamento de logs concluído');
finally
qArquivarLogs.Close;
qCopia.Close;
qDelete.Close;
Self.Conectado := false;
if qDelete <> nil then
FreeAndNil(qDelete);
if qCopia <> nil then
FreeAndNil(qCopia);
end;
end;
verifique se isso vai dar certo.
fiz todas as alterações no bloco de notas, pois estou sem o Delphi nesta máquina, então nem sei se a sintaxe está correta.
optei por 5.000 registros por vez. talvez a performance ainda seja boa selecionando 10.000 ou 15.000. faça os testes e veja se esta alteração surte algum efeito e se aumentar o número de registros ainda o torna satisfatório.
GOSTEI 0
Command Informatica
17/11/2010
Emerson, entendi suas idéias. Vou testar e depois informo os resultados.
Muito obrigado.
Muito obrigado.
GOSTEI 0
Anderson
17/11/2010
Bom dia, não utilizo o IBX, mas já verificou:
CommitRetaining na transação geraria perda de performance.
CachedUpdates pode estar amarrando o sistema.
O Tamanho da Página (Page size) do banco de dados (.fdb) está de acordo com a estrutura e utilização ?
A máquina e o sistema operacional são adequados para esta carga de trabalho ? (Hardware bem dimensionado, servidor dedicado rodando Linux ou Windows Server, ...)
Abraços,
Anderson:.
CommitRetaining na transação geraria perda de performance.
CachedUpdates pode estar amarrando o sistema.
O Tamanho da Página (Page size) do banco de dados (.fdb) está de acordo com a estrutura e utilização ?
A máquina e o sistema operacional são adequados para esta carga de trabalho ? (Hardware bem dimensionado, servidor dedicado rodando Linux ou Windows Server, ...)
Abraços,
Anderson:.
GOSTEI 0
Command Informatica
17/11/2010
Bom dia Anderson,
Muito obrigado pelas dicas
* Eu não utilizo commitRetaining.
* Nenhuma query que uso está com chached updates
* Já em relação ao page size eu vou verificar, mas não sei qual se enquadraria melhor.
* O Sistema operacional que utilizo é o windows XP professional em uma máquina Intel Core 2 Duo com 2 GB de memória ram, porem esse é o meu ambiente de desenvolvimento. Quando a aplicação for executar será em uma máquina provavelmente com sistema windows server 2008 e com bem mais memória que a minha e processador mais potente, mas tenho como realizar testes no ambiente do cliente.
Muito obrigado pelas dicas
* Eu não utilizo commitRetaining.
* Nenhuma query que uso está com chached updates
* Já em relação ao page size eu vou verificar, mas não sei qual se enquadraria melhor.
* O Sistema operacional que utilizo é o windows XP professional em uma máquina Intel Core 2 Duo com 2 GB de memória ram, porem esse é o meu ambiente de desenvolvimento. Quando a aplicação for executar será em uma máquina provavelmente com sistema windows server 2008 e com bem mais memória que a minha e processador mais potente, mas tenho como realizar testes no ambiente do cliente.
GOSTEI 0
Anderson
17/11/2010
A alguns anos fiz testes com Delphi + Componentes UIB + Windows e Kylix (agora finado) + Componentes UIB + Linux.
A máquina estava com dual boot, então o teste foi no mesmo hardware.
Em Windows o sistema ficava sentindo a carga, iniciando um processo de lentidão.
Em Linux o sistema manteve a velocidade constante.
Testei também, em ambos os ambientes (IBX e UIB). O UIB foi mais rápido.
O teste consistia em incluir um pouco mais de 53 milhões de registro. Na época, a performance das máquinas era bem inferior as das atuais e o processo levou um pouco mais de 4 horas em ambiente Linux, no Windows XP já estava em mais de 6 horas (desisti). Talves o resultado seja diferente se usar uma versão Server do Windows.
O UIB (Unified Interbase - http://www.progdigy.com/) é compatível com o Firebird.
O IBX não tem garantias de compatibilidade com o Firebird (principalmente em BLOBs'). Dos livros que tenho, quando surge o assunto IBX, todos tem a mesma opinão: não é recomendável usar por não haver garantia de compatibilidade pelo fabricante.
No livro The Firebird Book: A Reference for Database Developers da Helen Borrie, e em alguns outros livros e fóruns, há relatos de que a performance do Firebird é melhor em sistemas Linux (opinião compartilhada entre usuários, segundo a autora).
Utilizar o componente "com garantia" de compatibilidade pelo fabricante, além de evitar problemas de funcionamento, poderá explorar melhor os recursos (e desempenho), pois levará em conta as peculiaridades do banco de dados acessado.
Poderia (sugestão) testar com outros componentes: UIB, IBDAC ou Zeos. Faça uma aplicação de teste bem simples, para poder validar mais rapidamente qual a melhor solução.
Destes, o IBDAC é pago, mas tem um ciclo de atualizações/correções bem mais frequente que os demais.
O UIB e o Zeos não tem DataSets editáveis (tipo TClientDataSet). Mas para esta tarefa, que requer mais músculos que praticidade, deverão cumprir bem o papel, sem maiores complicações.
Há ainda a questão das versões do Firebird (Classic, SuperServer e agora a SuperClassic).
Em meus testes, ficou assim (é opinião pessoal e cada caso é um caso):
A Classic não é tão rápida quanto a SuperServer, porém é mais estável e mais constante em termos de velocidade.
A SuperServer é mais rápida mas, em meus testes se mostrou mais problemática (estabilidade).
A SuperClassic é mais rápida que a Classic (percepção imediata do usuário) e mantém a estabilidade e performance.
Hoje estou usando o Firebird 2.1 + DbExpress (é prático, mas pode não ser adequado para processamento massivo) em ambiente de produção e desenvolvimento. Com mais alguns testes e algum tempo após o lançamento da versão 2.5.1, se tudo correr conforme o planejado, passaremos para a versão SuperClassic.
Para trabalhar com qualquer banco de dados, é bom estar bem armado (conhecimento é tudo) para evitar/resolver os problemas. Tenho todos estes livros (excelentes, com dicas matadoras - Firebird - SQL - Sistema Operacional - Rotinas para o Usuário e Manutenção - Configurações - Hardware - ...):
- Dominando Firebird – HELEN BORRIE
- Programaçao Cliente/servidor com Firebird – CARLOS A. PEDROSO
- Firebird 2.0 – CARLOS H. CANTU
- Firebird Essencial – CARLOS H. CANTU
- Firebird – Dicas de Segurança – LUIZ PAULO SANTOS
Abraços,
Anderson:.
A máquina estava com dual boot, então o teste foi no mesmo hardware.
Em Windows o sistema ficava sentindo a carga, iniciando um processo de lentidão.
Em Linux o sistema manteve a velocidade constante.
Testei também, em ambos os ambientes (IBX e UIB). O UIB foi mais rápido.
O teste consistia em incluir um pouco mais de 53 milhões de registro. Na época, a performance das máquinas era bem inferior as das atuais e o processo levou um pouco mais de 4 horas em ambiente Linux, no Windows XP já estava em mais de 6 horas (desisti). Talves o resultado seja diferente se usar uma versão Server do Windows.
O UIB (Unified Interbase - http://www.progdigy.com/) é compatível com o Firebird.
O IBX não tem garantias de compatibilidade com o Firebird (principalmente em BLOBs'). Dos livros que tenho, quando surge o assunto IBX, todos tem a mesma opinão: não é recomendável usar por não haver garantia de compatibilidade pelo fabricante.
No livro The Firebird Book: A Reference for Database Developers da Helen Borrie, e em alguns outros livros e fóruns, há relatos de que a performance do Firebird é melhor em sistemas Linux (opinião compartilhada entre usuários, segundo a autora).
Utilizar o componente "com garantia" de compatibilidade pelo fabricante, além de evitar problemas de funcionamento, poderá explorar melhor os recursos (e desempenho), pois levará em conta as peculiaridades do banco de dados acessado.
Poderia (sugestão) testar com outros componentes: UIB, IBDAC ou Zeos. Faça uma aplicação de teste bem simples, para poder validar mais rapidamente qual a melhor solução.
Destes, o IBDAC é pago, mas tem um ciclo de atualizações/correções bem mais frequente que os demais.
O UIB e o Zeos não tem DataSets editáveis (tipo TClientDataSet). Mas para esta tarefa, que requer mais músculos que praticidade, deverão cumprir bem o papel, sem maiores complicações.
Há ainda a questão das versões do Firebird (Classic, SuperServer e agora a SuperClassic).
Em meus testes, ficou assim (é opinião pessoal e cada caso é um caso):
A Classic não é tão rápida quanto a SuperServer, porém é mais estável e mais constante em termos de velocidade.
A SuperServer é mais rápida mas, em meus testes se mostrou mais problemática (estabilidade).
A SuperClassic é mais rápida que a Classic (percepção imediata do usuário) e mantém a estabilidade e performance.
Hoje estou usando o Firebird 2.1 + DbExpress (é prático, mas pode não ser adequado para processamento massivo) em ambiente de produção e desenvolvimento. Com mais alguns testes e algum tempo após o lançamento da versão 2.5.1, se tudo correr conforme o planejado, passaremos para a versão SuperClassic.
Para trabalhar com qualquer banco de dados, é bom estar bem armado (conhecimento é tudo) para evitar/resolver os problemas. Tenho todos estes livros (excelentes, com dicas matadoras - Firebird - SQL - Sistema Operacional - Rotinas para o Usuário e Manutenção - Configurações - Hardware - ...):
- Dominando Firebird – HELEN BORRIE
- Programaçao Cliente/servidor com Firebird – CARLOS A. PEDROSO
- Firebird 2.0 – CARLOS H. CANTU
- Firebird Essencial – CARLOS H. CANTU
- Firebird – Dicas de Segurança – LUIZ PAULO SANTOS
Abraços,
Anderson:.
GOSTEI 0
Command Informatica
17/11/2010
Anderson,
Agradeço imensamente pelas dicas e pelo compartilhamento de seus conhecimentos.
Vou procurar os livros que você sugeriu para aprimorar meus conhecimentos.
Em relação às dicas anteriores eu fiz o que sugeriu (FIRST 5000). Melhorou a performance, porem ainda está caindo. A Valocidade em um teste que fiz começou em torno de 140 registros/segundo. agora após mais de 2 horas de processamento está entorno de 130 registros / segundo. Considerando que estou em 14% então essa velocidade vai cair bem mais até o final.
Suas dicas ajudaram bastantes.
Agradeço novamente.
Agradeço imensamente pelas dicas e pelo compartilhamento de seus conhecimentos.
Vou procurar os livros que você sugeriu para aprimorar meus conhecimentos.
Em relação às dicas anteriores eu fiz o que sugeriu (FIRST 5000). Melhorou a performance, porem ainda está caindo. A Valocidade em um teste que fiz começou em torno de 140 registros/segundo. agora após mais de 2 horas de processamento está entorno de 130 registros / segundo. Considerando que estou em 14% então essa velocidade vai cair bem mais até o final.
Suas dicas ajudaram bastantes.
Agradeço novamente.
GOSTEI 0