Einzelnen Beitrag anzeigen

Delphi.Narium

Registriert seit: 27. Nov 2017
2.508 Beiträge
 
Delphi 7 Professional
 
#12

AW: Parametrisiertes Insert plötzlich abnormal langsam

  Alt 9. Jan 2023, 17:15
Wenn sichergestellt ist, dass das Problem tatsächlich aus Deinem Programm kommt (und nicht eine der vielen Möglichkeiten, die Jasocul aufführt, als Ursache in Betracht kommt):

Wie sieht das Transaktionshandling aus?
Eine Transaktion je ExecSQL oder eine Transaktion je while NOT (Que_L_Export.Eof) do , also alles aus einer Tabelle innerhalb einer Transaktion verarbeiten?

Statt je Datensatz immer wieder alle Parameter und Felder zu suchen, diese vorher als entsprechende Variabeln deklarieren und einmalig suchen lassen. Sowas in der Art:
Delphi-Quellcode:
var
  pIDVonQuelle : TParam;
  pParamID : TParam;
  pDelta : TParam;
  pAnzahl : TParam;
  pZeit : TParam;
  fID : TField;
  fParamID : TField;
  fDelta : TField;
  fAnzahl : TField;
  fGeaendert_am : TField;
begin
  ...
  pIDVonQuelle := Que_G_MengenLogbuch_Insert.Params.FindParam('IDVonQuelle');
  pParamID := Que_G_MengenLogbuch_Insert.Params.FindParam('ParamID');
  pDelta := Que_G_MengenLogbuch_Insert.Params.FindParam('Delta');
  pAnzahl := Que_G_MengenLogbuch_Insert.Params.FindParam('Anzahl');
  pZeit := Que_G_MengenLogbuch_Insert.Params.FindParam('Zeit');
  
  fID := Que_L_Export.FindField('ID');
  fParamID := Que_L_Export.FindField('ParamID');
  fDelta := Que_L_Export.FindField('Delta');
  fAnzahl := Que_L_Export.FindField('Anzahl');
  fGeaendert_am := Que_L_Export.FindField('geaendert_am');

  while NOT (Que_L_Export.Eof) do
   begin
     pIDVonQuelle.AsInteger := fID.AsInteger;
     pParamID.AsInteger := fParamID.AsInteger;
     pDelta.AsInteger := fDelta.AsInteger;
     pAnzahl.AsInteger := fAnzahl.AsInteger;
     fGeaendert_am.AsDateTime := fGeaendert_am.AsDateTime;
     if NOT(Que_G_MengenLogbuch_Insert.Prepared) then Que_G_MengenLogbuch_Insert.Prepare();
     Que_G_MengenLogbuch_Insert.Execute();
     Que_L_Export.Next;
   end;
  ...
Bei großen Datenmengen kann sich das, auch wenn es erstmal nach banalem, vermeidbarem, Mehraufwand im Quelltext aussieht, (aus meiner Erfahrung heraus) durchaus positiv auf die Laufzeit (auf Clientebene) auswirken.

Bei den Parametern hast Du zusätzlich den Vorteil, dass Du den DataType und den ParamType angeben kannst und nicht darauf hoffen musst, dass die Datenbanksschnittstelle schon das Richtige machen wird.

Mit einh bisserl Glück kannst Du so das
Zitat von mariusbenz:
(wenn ich es davor setze, kommen irgendwelche CONVERT variant Exceptions)
vermeiden.

Also zusätzlich noch sowas in der Art:
Delphi-Quellcode:
  pIDVonQuelle.DataType := ftInteger;
  pParamID.DataType := ftInteger;
  pDelta.DataType := ftInteger;
  pAnzahl.DataType := ftInteger;
  pZeit.DataType := ftDateTime;
  pIDVonQuelle.ParamType := ptInput;
  pParamID.ParamType := ptInput;
  pDelta.ParamType := ptInput;
  pAnzahl.ParamType := ptInput;
  pZeit.ParamType := ptInput;
Damit müsstest Du das Prepare vor die While-Schleife setzen können.
Gibt es eine Garantie, dass das dann im realen (Datenbank)Leben wirklich was bringt? Nein, aber eventuell ist's 'nen Versuch wert.

Zitat von mariusbenz:
Unseren blöden Antivirus habe ich mittlerweile grundsätzlich als Hauptverdächtigen, allerdings passt es irgendwie nicht, dass plötzlich eine einzelne Abfrage deswegen 1000x langsamer wird
Doch, die können bei 'nem Update durchaus auch mal "Bockmist" gebaut haben und nun z. B. Datenbankdateien mit scannen, was sie vor dem Update nicht gemacht haben, irgendwelche konfigurierten Ausnahmeregeln nicht mehr beachten, ... Da kann schon ziemlich viel passieren, auf das Du erstmal keinen Einfluss hast, weil solches "Fehlverhalten" nicht zwingend offensichtlich ist.

Die DB ist laut Screenshot ca. 21 GB groß. Und die wird in Schritten von 1 Megabyte vergrößert?

Welche Datenmengen habt Ihr denn da? Könnte es sein, dass der Datenbankserver "fast ausschließlich" mit dem Vergrößern der Datenbankdatei beschäftigt ist? Und wenn die Platte dann stark fragmentiert ist oder sehr voll, wird sowas durchaus auch schonmal "etwas langsamer".

Das kann auch das "Plötzlich von jetzt auf gleich" für's Langsamwerden begründen. Bis 20 GB Ursprungsgröße war die Datenbankdatei ausreichend dimensioniert und ab 20 GB + 1 MB wird "alle Nase lang" vergrößert.

Berechne bitte mal grob die Datenmenge, die Du pro Aufruf Deiner Routine in etwa in die Datenbank schreiben musst, also nicht nur hier die langsame Routine, sondern auch die Protokollstatements, die in eine andere Tabelle geschrieben werden ... (ggfls. auch andere Prozesse, die in die Datenbank schreiben, beachten). Für wieviele Programmaufrufe reicht dann 1 Megabyte aus? Die 1 Megabyteschritte kämen für mich nur bei einer Datenbank mit marginalem Zuwachs in frage. (Flapsig formuliert: Der Zuwachs sollte schon für die nächsten ein oder zwei Wochen reichen )

Und: Alles was Jasocul schreibt, sollte vorab überprüft bzw. durchgeführt werden.
  Mit Zitat antworten Zitat