Entwickler-Ecke

Datenbanken - Offene Datenbankverbindungen/Fehler:zu viele offene Tabellen


jjturbo - Di 26.06.07 09:17
Titel: Offene Datenbankverbindungen/Fehler:zu viele offene Tabellen
Moin Forum,

kann man sich irgendwie anzeigen lassen, wie viele Datenbankverbindungen (m)eine Applikation offen hat?

Danke im voraus, jjturbo


BenBE - Di 26.06.07 09:32

Wenn Du auf einen MySQL-Server zugreifst, kannst Du das mit SHOW FULL PROCESSLIST machen. Für andere Datenbanken wird es da sicherlich auch Wege geben.


jjturbo - Di 26.06.07 15:05

Ich habe mal wieder ein Problem, und das nennt sich "Zu viele offene Tabellen vorhanden"
Jetzt habe ich die Stelle gefunden, wo in meinem Programm der Fehler auftritt.
Bei der aktuell verwendeten Datenmenge tritt der Fehler jedes mal exakt beim einundzwanzigsten Aufruf dieser Prozedur auf, und zwar bei "QueryBearbdaten.Active := True;"

Anbei der Quellcode der Prozedur. Sieht da jemand ein Problem?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
procedure TMyProc.BearbeitungEinfuegen(PosStr1:String;TeilNr:Integer;AnschnittWinkel:Real);
var SQLText         :String;
    Tabellenname    :String;
    Verz            :String;
    PosStr2         :String;
    PosReal         :Real;
    Winkel          :Real;
    XPos            :Real;
    VersatzBohrer   :Real;
    EffSaegeblBrLi  :Real;
    QueryBearbdaten :TQuery;
begin

  QueryBearbdaten            := TQuery.Create(HauptForm);
  QueryBearbdaten.DataSource := HauptForm.DataSourceBearbdaten;

  Tabellenname                := ExtractFilename(HauptForm.TableBearbdaten.TableName);
  Verz                        := ExtractFilePath(HauptForm.TableBearbdaten.TableName);

  SQLText                     := 'SELECT * from ' + Tabellenname + ' WHERE teilnr = ' + QuotedStr(IntToStr(TeilNr));
  protokoll(clgreen,'SQL: ' + SQLText);




  QueryBearbdaten.SQL.Clear;
  QueryBearbdaten.SQL.SetText(PChar(SQLText));
  QueryBearbdaten.DatabaseName := Verz;
  QueryBearbdaten.ExecSQL;






  TRY
  QueryBearbdaten.Active := True;
  EXCEPT
    QueryBearbdaten.Active := false;
    FreeAndNil(QueryBearbdaten);
    protokoll(clRed,'Fehler beim Öffnen der Bearbeitungsdaten');
    Exit;
  END;



  QueryBearbdaten.First;
  while not QueryBearbdaten.Eof do begin

    Winkel         := QueryBearbdaten.FieldbyName('Winkel').AsFloat;
    XPos           := QueryBearbdaten.FieldbyName('X').AsFloat;
    VersatzBohrer  := DrehpunktHinterNull_Bohrer * tan(Winkel*pi/180);
    EffSaegeblBrLi := EffektiveSaegeblattBreite(SaegeblattBreiteZangenseitig,0,AnschnittWinkel);

    PosReal        := StrToFloat(PosStr1) - EffSaegeblBrLi*1000 - XPos*1000 + OffsetBohrer*1000 + VersatzBohrer*1000;
    PosReal        := Round(PosReal/100)*100;
    PosStr2        := FormatFloat('00000000',PosReal);

    HauptForm.TableSPSDaten.Append;
    HauptForm.TableSPSDaten.FieldByName('ZangenPosition').AsString    := PosStr2;
    HauptForm.TableSPSDaten.FieldByName('Bearb').AsString             := QueryBearbdaten.FieldbyName('Bearb').AsString;
    HauptForm.TableSPSDaten.FieldByName('TeilNr').AsInteger           := TeilNr;
    HauptForm.TableSPSDaten.FieldByName('Länge').AsInteger            := 0;
    HauptForm.TableSPSDaten.FieldByName('Winkel').AsFloat             := Winkel;
    HauptForm.TableSPSDaten.FieldByName('WertSchwenkachse').AsInteger := SollWertSchwenkachseBerechnen(Winkel);
    HauptForm.TableSPSDaten.FieldByName('Y').AsFloat                  := QueryBearbdaten.FieldbyName('Y').AsFloat;
    HauptForm.TableSPSDaten.FieldByName('Z').AsFloat                  := QueryBearbdaten.FieldbyName('Z').AsFloat;
    QueryBearbdaten.Next;

  end;//while not QueryBearbdaten.Eof do begin



  QueryBearbdaten.Close;
//  QueryBearbdaten.Active := false;
  FreeAndNil(QueryBearbdaten);

end;


Danke im voraus, jjturbo


jjturbo - Di 26.06.07 16:50

...acho so: Verwendet werden lokale Paradox-Tabellen und die BDE


kkausp - Di 26.06.07 18:28

Ich habe es mal ein bisschen geändert. Mit freeandnil hatte ich mal Probleme. Ansonsten vermute ich das eventuell in der Schleife eine exception auftritt und die qeury nicht mehr freigeben wird.

Die subroutienen rufen keine DB mehr auf?



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
procedure TMyProc.BearbeitungEinfuegen(PosStr1:String;TeilNr:Integer;AnschnittWinkel:Real);
var SQLText         :String;
    Tabellenname    :String;
    Verz            :String;
    PosStr2         :String;
    PosReal         :Real;
    Winkel          :Real;
    XPos            :Real;
    VersatzBohrer   :Real;
    EffSaegeblBrLi  :Real;
    QueryBearbdaten :TQuery;
begin

  QueryBearbdaten            := TQuery.Create(HauptForm);
try 
try 
 QueryBearbdaten.DataSource := HauptForm.DataSourceBearbdaten; //hier ist mir nicht klar wozu????

  Tabellenname                := ExtractFilename(HauptForm.TableBearbdaten.TableName);
  Verz                        := ExtractFilePath(HauptForm.TableBearbdaten.TableName);

  SQLText                     := 'SELECT * from ' + Tabellenname + ' WHERE teilnr = ' + QuotedStr(IntToStr(TeilNr));
  protokoll(clgreen,'SQL: ' + SQLText);




  QueryBearbdaten.SQL.Clear;
  QueryBearbdaten.SQL.SetText(PChar(SQLText));
  QueryBearbdaten.DatabaseName := Verz;
  QueryBearbdaten.ExecSQL;


  QueryBearbdaten.Active := True;
  QueryBearbdaten.First;
  while not QueryBearbdaten.Eof do begin

    Winkel         := QueryBearbdaten.FieldbyName('Winkel').AsFloat;
    XPos           := QueryBearbdaten.FieldbyName('X').AsFloat;
    VersatzBohrer  := DrehpunktHinterNull_Bohrer * tan(Winkel*pi/180);
    EffSaegeblBrLi := EffektiveSaegeblattBreite(SaegeblattBreiteZangenseitig,0,AnschnittWinkel);

    PosReal        := StrToFloat(PosStr1) - EffSaegeblBrLi*1000 - XPos*1000 + OffsetBohrer*1000 + VersatzBohrer*1000;
    PosReal        := Round(PosReal/100)*100;
    PosStr2        := FormatFloat('00000000',PosReal);

    HauptForm.TableSPSDaten.Append;
    HauptForm.TableSPSDaten.FieldByName('ZangenPosition').AsString    := PosStr2;
    HauptForm.TableSPSDaten.FieldByName('Bearb').AsString             := QueryBearbdaten.FieldbyName('Bearb').AsString;
    HauptForm.TableSPSDaten.FieldByName('TeilNr').AsInteger           := TeilNr;
    HauptForm.TableSPSDaten.FieldByName('Länge').AsInteger            := 0;
    HauptForm.TableSPSDaten.FieldByName('Winkel').AsFloat             := Winkel;
    HauptForm.TableSPSDaten.FieldByName('WertSchwenkachse').AsInteger := SollWertSchwenkachseBerechnen(Winkel);
    HauptForm.TableSPSDaten.FieldByName('Y').AsFloat                  := QueryBearbdaten.FieldbyName('Y').AsFloat;
    HauptForm.TableSPSDaten.FieldByName('Z').AsFloat                  := QueryBearbdaten.FieldbyName('Z').AsFloat;

   
    HauptForm.TableSPSDaten.post; //der letzte soll auch gespeichert werden.

    QueryBearbdaten.Next;

  end;//while not QueryBearbdaten.Eof do begin



  QueryBearbdaten.Close;
//  QueryBearbdaten.Active := false;

  EXCEPT
    protokoll(clRed,'Fehler');
  END;

finally
  QueryBearbdaten.free;
end;
end;


raiguen - Di 26.06.07 18:54

Moin :-)
Ähm... das hier

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  QueryBearbdaten            := TQuery.Create(HauptForm);
  QueryBearbdaten.DataSource := HauptForm.DataSourceBearbdaten;

  Tabellenname                := ExtractFilename(HauptForm.TableBearbdaten.TableName);
  Verz                        := ExtractFilePath(HauptForm.TableBearbdaten.TableName);
  SQLText                     := 'SELECT * from ' + Tabellenname + ' WHERE teilnr = ' + QuotedStr(IntToStr(TeilNr));

ist m.E. nicht unbedingt sinnvoll :roll: Ich nehme mal sehr stark an, dass sich Tabellenname und Verz nicht ändern, also quasi 'constant' sind?

Ich würde so vorgehen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
...
   private
     QueryBearbDaten: TQuery;
   public
    ....

procedure TMyProc.BearbeitungEinfuegen(PosStr1:String;TeilNr:Integer;AnschnittWinkel:Real);
var SQLText         :String;
    Tabellenname    :String;
    Verz            :String;
    PosStr2         :String;
    PosReal         :Real;
    Winkel          :Real;
    XPos            :Real;
    VersatzBohrer   :Real;
    EffSaegeblBrLi  :Real;
begin
  if not Assigned(QueryBearDaten) then
    begin
      Tabellenname                 := ExtractFilename(HauptForm.TableBearbdaten.TableName);
      Verz                         := ExtractFilePath(HauptForm.TableBearbdaten.TableName);
      QueryBearbdaten              := TQuery.Create(HauptForm); 
      QueryBearbdaten.DatabaseName := Verz;

      //--wozu ist das gut??
      QueryBearbdaten.DataSource := HauptForm.DataSourceBearbdaten;
      //--
  end;

  //--Abfrage vorbereiten
  if not QueryBearbDaten.Prepared then 
    begin
      QueryBearbDaten.SQLText := 'SELECT * FROM ' + Tabellenname + ' WHERE teilnr = :TEILNR ';
      QueryBEarDaten.Prepare;
  end;
  
  //--Parameter einsetzen, vorher Abfrage schliessen 
  QueryBearbDaten.Close; //--oder QueryBearbDaten.Active := false;
  QueryBearbDaten.Params[0].AsString := IntToStr(TeilNr);
  QueryBearbDaten.Open; //-- oder QueryBearbDaten.Active := true; 
   ...
end;

Die QueryBEarbDaten wird nur einmal erstellt, sofern sie noch nicht vorhanden ist und mit dem entsprechenden SQL-Statement und Parameter vorbereitet. Bei jedem weiteren Durchlauf der Procedure wird nur der PArameter übergeben... Das spart Rechnerzeit und ständiges Allozieren/Freigeben von Speicher durch den SQL-Server (auch wenn's nur die BDE-eigene Geschichte ist...)
Beim Beenden der HAuptform als Owner wird QueryBEarbDaten automatisch mit freigegeben...


jjturbo - Di 26.06.07 20:27

Danke erst mal für Eure Anregungen und Kommentare.
Ich habe damit mal ein wenig getestet, es hat aber leider nichts gebracht.

Es treten keine weiteren Exceptions auf, weitere DB-Aufrufe in den Subroutinen gibt es nicht.
Tabellenname ändert sich gelegentlich(wenn ein anderer Auftrag gefahren wird), Verz könnte sich auch ändern.

Ich sehe eigentlich nichts grundlegend falsches... :(


jjturbo - Mi 27.06.07 09:02

So, ich habe die TQuery jetz[/delphi]t mal rausgeschmissen und hole mir die benötigten Daten über TTable mit Hilfe eines Filters:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
procedure TMyProc.BearbeitungsdatenFiltern(TeilNr:Integer);
var TeilNrStr :String;
begin

  TeilNrStr := IntToSTr(TeilNr);

  with HauptForm.TableBearbdaten do begin
    Active     := false;
    Filter     := 'TeilNr = ' + QuotedStr(TeilNrStr);
    Filtered   := True;
    Active     := True;
  end;


end;





procedure TMyProc.BearbeitungsdatenFilternAus;
begin

  with HauptForm.TableBearbdaten do begin
    Active     := false;
    Filtered   := false;
    Active     := True;
  end;


end;





procedure TMyProc.BearbeitungEinfuegen(PosStr1:String;TeilNr:Integer;AnschnittWinkel:Real);
var PosStr2         :String;
    PosReal         :Real;
    Winkel          :Real;
    XPos            :Real;
    VersatzBohrer   :Real;
    EffSaegeblBrLi  :Real;
begin

  BearbeitungsdatenFiltern(TeilNr);


  HauptForm.TableBearbdaten.First;
  while not HauptForm.TableBearbdaten.Eof do begin

    Winkel         := HauptForm.TableBearbdaten.FieldbyName('Winkel').AsFloat;
    XPos           := HauptForm.TableBearbdaten.FieldbyName('X').AsFloat;
    VersatzBohrer  := DrehpunktHinterNull_Bohrer * tan(Winkel*pi/180);
    EffSaegeblBrLi := EffektiveSaegeblattBreite(SaegeblattBreiteZangenseitig,0,AnschnittWinkel);

    PosReal        := StrToFloat(PosStr1) - EffSaegeblBrLi*1000 - XPos*1000 + OffsetBohrer*1000 + VersatzBohrer*1000;
    PosReal        := Round(PosReal/100)*100;
    PosStr2        := FormatFloat('00000000',PosReal);

    HauptForm.TableSPSDaten.Append;
    HauptForm.TableSPSDaten.FieldByName('ZangenPosition').AsString    := PosStr2;
    HauptForm.TableSPSDaten.FieldByName('Bearb').AsString             := HauptForm.TableBearbdaten.FieldbyName('Bearb').AsString;
    HauptForm.TableSPSDaten.FieldByName('TeilNr').AsInteger           := TeilNr;
    HauptForm.TableSPSDaten.FieldByName('Länge').AsInteger            := 0;
    HauptForm.TableSPSDaten.FieldByName('Winkel').AsFloat             := Winkel;
    HauptForm.TableSPSDaten.FieldByName('WertSchwenkachse').AsInteger := SollWertSchwenkachseBerechnen(Winkel);
    HauptForm.TableSPSDaten.FieldByName('Y').AsFloat                  := HauptForm.TableBearbdaten.FieldbyName('Y').AsFloat;
    HauptForm.TableSPSDaten.FieldByName('Z').AsFloat                  := HauptForm.TableBearbdaten.FieldbyName('Z').AsFloat;
    HauptForm.TableSPSDaten.Post;
    HauptForm.TableBearbdaten.Next;
  end;//while not HauptForm.TableBearbdaten.Eof do begin




  BearbeitungsdatenFilternAus;

end;


Es werden die gleichen Daten abgefragt, der Fehler scheint aber damit behoben zu sein.

Dennoch würde mich interessieren wo der Fehler liegt.