Pętla coraz wolniej

0

Mam pętle która z przelatuje po rekordach w datasecie i coś z nimi robi i zapisuje do bazy danych.
Dla każdego rekordu wykonuje takie same operacje, ale im więcej rekordów tym dłużej pętla działa.
Chodzi mi o to, że każdy kolejny rekord wykonuje sie dłużej.
Podczas gdy początkowe wykonują się po kilka na sekunde, to te powyżej 100 działają 1 na 5 sekund.
Te dalsze jeszcze wolniej.

Jakieś pomysły co mogę z tym zrobić ?

P.S. Program jest w Delphi a baza danych MSSQL. Komponenty ADO.

0

musisz to dobrze zaprogramować bo tak jak teraz to będzie wolno działać.

0

Robisz to online'owo czy offline'owo, a później wszystko do bazy wrzucasz? Pokaż kod odpowiedzialny za to.

0

Dawno nie musiałem użyć komponentów bazodanowych w delphi, ale daj nam może więcej informacji, może kawałek kodu :) Może tam masz coś skopanego?

0

Ta procedura jest wywoływana w pętli dla każdego rekordu zaczytanego z Excela.

 
procedure ZapisLokalu(NrWiersza: integer);
var powierzchnia:Currency;
    i:Byte;
    kod_powierzchnia:string[4];
begin
  Result:= 0;
     if DM.temp.Active then DM.temp.Close;
      DM.temp.CommandText:=
        //zapytanie pobierające z bazy dane potrzebne przy dodawaniu nowego lokalu
      DM.temp.Open;

  ADOCommand1.CommandText:=
    ' INSERT INTO Lokal() ' //dodanie nowego lokalu

  ADOCommand1.Parameters.ParamByName('nr_ew1').Value:= DaneImportu[NrWiersza,18];
  ADOCommand1.Parameters.ParamByName('nr_ew2').Value:= DaneImportu[NrWiersza,19];
  ADOCommand1.Parameters.ParamByName('LokalUlica').Value:= DaneImportu[NrWiersza,20];
  ADOCommand1.Parameters.ParamByName('adres_nrdom').Value:= DaneImportu[NrWiersza,21];
  ADOCommand1.Parameters.ParamByName('adres_nrlokal').Value:= DaneImportu[NrWiersza,22];
  ADOCommand1.Parameters.ParamByName('nr_klatki').Value:= DaneImportu[NrWiersza,23];
  //ADOCommand1.Parameters.ParamByName('id_typ1').Value:= StrToIntDef(DaneImportu[NrWiersza,24],0);
  //ADOCommand1.Parameters.ParamByName('id_typ2').Value:= StrToIntDef(DaneImportu[NrWiersza,25],0);
  if DM.temp.RecordCount>0 then ADOCommand1.Parameters.ParamByName('id_typ1').Value:=DM.temp.Fields[0].AsInteger
     else ADOCommand1.Parameters.ParamByName('id_typ1').Value:= StrToIntDef(DaneImportu[NrWiersza,24],0);
  if DM.temp.RecordCount>0 then ADOCommand1.Parameters.ParamByName('id_typ2').Value:=DM.temp.Fields[1].AsInteger
     else ADOCommand1.Parameters.ParamByName('id_typ2').Value:= StrToIntDef(DaneImportu[NrWiersza,25],0);
  ADOCommand1.Parameters.ParamByName('ilosc_osob').Value:= StrToIntDef(DaneImportu[NrWiersza,26],0);

  if DaneImportu[NrWiersza,27] <> '' then
    ADOCommand1.Parameters.ParamByName('powierzchnia').Value:= StrToCurr(StringReplace(DaneImportu[NrWiersza,27],'.',',',[rfReplaceAll,rfIgnoreCase]))
  else ADOCommand1.Parameters.ParamByName('powierzchnia').Value:= 0;

  if DaneImportu[NrWiersza,28] <> '' then
    ADOCommand1.Parameters.ParamByName('pow_mieszkalna').Value:= StrToCurr(StringReplace(DaneImportu[NrWiersza,28],'.',',',[rfReplaceAll,rfIgnoreCase]))
  else ADOCommand1.Parameters.ParamByName('pow_mieszkalna').Value:= 0;

  if DaneImportu[NrWiersza,29] <> '' then
    ADOCommand1.Parameters.ParamByName('pow_uzytkowa').Value:= StrToCurr(StringReplace(DaneImportu[NrWiersza,29],'.',',',[rfReplaceAll,rfIgnoreCase]))
  else ADOCommand1.Parameters.ParamByName('pow_uzytkowa').Value:= 0;

  ADOCommand1.Parameters.ParamByName('udzial_pow_wspolnej_proc').Value:= StrToFloatDef(DaneImportu[NrWiersza,35],0);
  ADOCommand1.Parameters.ParamByName('nrks_wiecz').Value:= DaneImportu[NrWiersza,36];
  ADOCommand1.Parameters.ParamByName('konto').Value:= DaneImportu[NrWiersza,37];
  ADOCommand1.Execute;

  Result:= DajIdentity('Lokal');  //pobiera id wstawionego lokalu
    Application.ProcessMessages;

  for i:=30 to 34 do
  begin
    if StrToCurrDef(DaneImportu[NrWiersza,i],0)>0 then    // dodatkowe powierzchnie dla lokalu
    begin
      case i of
        30: kod_powierzchnia:='PD';
        31: kod_powierzchnia:='PG';
        32: kod_powierzchnia:='PH';
        33: kod_powierzchnia:='PM';
        34: kod_powierzchnia:='PU';
      end;
      ADOCommand1.CommandText:=
          'DECLARE @id_powierzchnia INT,' + #13#10 +
                  '@kod_powierzchnia VARCHAR(4),' + #13#10 +
                  '@id_lokal INT,' + #13#10 +
                  '@wielkosc MONEY' + #13#10 +
          'SET @kod_powierzchnia = '+ QuotedStr(kod_powierzchnia) + #13#10 +
          'SET @id_powierzchnia = ISNULL((SELECT TOP 1 ID_POWIERZCHNIA FROM SL_POWIERZCHNIA WHERE KOD_POWIERZCHNIA=@kod_powierzchnia),0)' + #13#10 +
          'SET @id_lokal = '+IntToStr(Result) + #13#10 +
          'SET @wielkosc = '+StringReplace(DaneImportu[NrWiersza,i],',','.',[rfReplaceAll, rfIgnoreCase]) + #13#10 +
          'IF @id_powierzchnia>0' + #13#10 +
          'IF NOT EXISTS(SELECT * FROM LOKAL_POW WHERE id_lokal=@id_lokal AND ID_POWIERZCZNIA=@id_powierzchnia)' + #13#10 +
          'INSERT INTO LOKAL_POW(ID_LOKAL,ID_POWIERZCZNIA,WIELKOSC)' + #13#10 +
          'VALUES (@id_lokal, @id_powierzchnia, @wielkosc)';
       ADOCommand1.Execute;
    end;
    Application.ProcessMessages;
  end;
 

DaneImportu to stablica stringów. Przechowuje dane zaczytanie z Excela.
Jej rozmiar jest równy ilości wypełnionych kolumn i wierszy w arkuszu Excela.

1

Cześć Paweł :)
Na czas importu wyłącz triggera podliczającego powierzchnię na budynku z poszczególnych lokali ;)

0
  1. za każdym razem tworzysz polecenie od nowa - ŹLE! - polecenie tworzysz na początku, ustawiasz mu typy parametrów, robisz Prepare a potem tylko podstawiasz wartości pod parametry i robisz Execute.
  2. czy to tutaj
if DM.temp.Active then DM.temp.Close;
      DM.temp.CommandText:=
        //zapytanie pobierające z bazy dane potrzebne przy dodawaniu nowego lokalu
      DM.temp.Open;

jest różne dla każdego wiersza - nie da się tego wykonać tylko raz?
3. tego

ADOCommand1.CommandText:=
          'DECLARE @id_powierzchnia INT,' + #13#10 +
                  '@kod_powierzchnia VARCHAR(4),' + #13#10 +
                  '@id_lokal INT,' + #13#10 +
                  '@wielkosc MONEY' + #13#10 +
          'SET @kod_powierzchnia = '+ QuotedStr(kod_powierzchnia) + #13#10 +
          'SET @id_powierzchnia = ISNULL((SELECT TOP 1 ID_POWIERZCHNIA FROM SL_POWIERZCHNIA WHERE KOD_POWIERZCHNIA=@kod_powierzchnia),0)' + #13#10 +
          'SET @id_lokal = '+IntToStr(Result) + #13#10 +
          'SET @wielkosc = '+StringReplace(DaneImportu[NrWiersza,i],',','.',[rfReplaceAll, rfIgnoreCase]) + #13#10 +
          'IF @id_powierzchnia>0' + #13#10 +
          'IF NOT EXISTS(SELECT * FROM LOKAL_POW WHERE id_lokal=@id_lokal AND ID_POWIERZCZNIA=@id_powierzchnia)' + #13#10 +
          'INSERT INTO LOKAL_POW(ID_LOKAL,ID_POWIERZCZNIA,WIELKOSC)' + #13#10 +
          'VALUES (@id_lokal, @id_powierzchnia, @wielkosc)';

to już w ogóle nie czaję :/ - tam gdzie pobierasz "dane potrzebne przy dodawaniu nowego lokalu" nie możesz sprawdzić czy lokal_pow istnieje i od tego uzależnić wykonanie bądź nie prostego inserta?
4. używaj znaczników <code class="delphi"> </code>

0

Ten kod to tragedia. Po pierwsze - czy za każdym razem musi się wykonywać zapytanie zaczytująe dane? Nie możesz zaczytać wszystkich danych raz, a potem posługiwać się odpowiednimi metodami?(next, eof, recNo, itd).
Poza tym pamiętaj, że operacje wykonywane bezpośrednio w bazie danych(tzn. zamiast iteracji na ADO) działają dużo szybciej. Może spróbuj przerobić ten kod na czyste zapytania?

1 użytkowników online, w tym zalogowanych: 0, gości: 1