Para nosso teste usamos ZeosLib. Por padrão o ZeosLib também opera no modo Auto-Commit, ou seja, cada comando é executado no contexto de uma transação. Não mostraremos aqui como conectar ao PG usando Zeos, pois isso já foi apresentado no post Lazarus - Conectando PostgreSQL com ZeosLib. Vejamos o primeiro teste. A unit Dateutils deve ser incluida na cláusula uses para poder usar a função
MilliSecondsBetween(). dbBanco é um ZConnection, dmDados é um Data Module e queCidade uma ZQuery.
var i: integer; a, b: TDateTime; begin dmDados.queCidade.SQL.Clear; dmDados.queCidade.SQL.Add('insert into cidade values (:id, :nome)'); a := time; for i := 1 to 5000 do begin dmDados.queCidade.ParamByName('ID').Value:= i; dmDados.queCidade.ParamByName('NOME').Value:='SANTAREM'; dmDados.queCidade.ExecSql; end; b := time; ShowMessage(IntToStr(MilliSecondsBetween(b,a))); end;
Neste primeiro código o tempo médio de inserção das 5.000 linhas foi de 11,6 segundos. Alteramos então nosso código para que todas as linhas fossem inseridas dentro de uma única transação. Para isso chamamos StartTransaction antes de iniciar os INSERTs. Observe o código abaixo.
var i: integer; a, b: TDateTime; begin a := time; dmDados.queCidade.SQL.Clear; dmDados.queCidade.SQL.Add('insert into cidade values (:id, :nome)'); dmDados.dbBanco.StartTransaction; for i := 1 to 5000 do begin dmDados.queCidade.ParamByName('ID').Value:= i; dmDados.queCidade.ParamByName('NOME').Value:='SANTAREM'; dmDados.queCidade.ExecSql; end; dmDados.dbBanco.Commit; b := time; ShowMessage(IntToStr(MilliSecondsBetween(b,a))); end;
Neste caso o tempo médio de execução do código foi de 2,9 segundos. Um ganho de tempo considerável em relação à execução em modo padrão.
Fizemos também um teste usando TZUpdateSQL, implementado de acordo com o post citado acima. O código é apresentado em seguida e o tempo médio de execução foi de 3,8 segundos. Um desempenho um pouco pior do que o teste anterior.
var i: integer; a, b: TDateTime; begin a := time; dmDados.queCidade.Open; dmDados.dbBanco.StartTransaction; for i := 1 to 5000 do begin dmDados.queCidade.Insert; dmDados.queCidade.FieldByName('ID').Value := i; dmDados.queCidade.FieldByName('NOME').Value:='SANTAREM'; dmDados.queCidade.Post;; end; dmDados.dbBanco.Commit; b := time; ShowMessage(IntToStr(MilliSecondsBetween(b,a))); end;
Estes teste foram feitos em Windows e servidor de BD e cliente rodando na mesma máquina. Certamente se você executar esses testes em outro ambiente, os tempos serão diferentes, mas comparativamente você deverá chegar à mesma conclusão.
Sabe-se que uma falha no sistema, enquanto uma transação estiver ativa, causa a execução de um ROLLBACK pelo SGBD, fazendo com que todas as atualizações feitas a partir do BEGIN sejam canceladas. Portanto, use esta recomendação com cautela e bom senso. Longas transações ativas estão sujeitas a perdas de dados muito maiores que transações curtas, em caso de falhas no sistema.
Atualizado em 28/09/2010.