Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi OnCalcFields... gibt es einen effizienteren Weg? (https://www.delphipraxis.net/132069-oncalcfields-gibt-es-einen-effizienteren-weg.html)

zack0r 5. Apr 2009 20:22

Datenbank: DBISAM • Version: 4 • Zugriff über: Direkt

OnCalcFields... gibt es einen effizienteren Weg?
 
Hallo,
ich bin an einer Software dran und habe ein Performance Problem. Lokal kann man arbeiten aber übers Netzwerk wird es schnell sehr träge. Hier ein Auszug aus dem Datenmodell:

Zitat:

Artikel
----
lfdnr (Primary Key)
bezeichnung
nachweise
behandlungszustand

Nachweise
----
idx (Primary Key)
nachweis

ArtikelNachweise
----
idx (Primary Key)
lfdnr (->Fremdschlüssel auf Artikel->lfdnr)
nachweisnr (->Fremdschlüssel auf Nachweise->idx)
Für das Feld Behandlungszustand gibt es auch entsprechende Tabellen. In der Tabelle Artikel sind noch etwa 20 weitere Felder.

In meinem Hauptfenster ist ein Grid das mit einem Query verbunden ist (qartikel). Hier der SQL-Code:
SQL-Code:
SELECT *
FROM artikel AS A LEFT OUTER JOIN bestellungenpos AS B ON A.lfdnr = B.artikel
ORDER BY lfdnr DESC
So, jetzt will in in diesem Grid die Datensätze aus Nachweise und Behandlungszustand anzeigen. Aber da es ja 1:N-Beziehung ist kann ich kein lookup-Feld einsetzen. Was ich will ist quasi eine mit Komma getrennte Anzeige der entsprechenden Datensätze. Dafür habe ich mich der OnCalcFields-Methode bedient. Dies funktioniert auch, aber ist leider recht langsam.
Jetzt meine Frage, fällt jemandem ein Weg ein wie man das Effizienter und Performanter implementieren kann?

Delphi-Quellcode:
procedure Tfmain.qartikelCalcFields(DataSet: TDataSet);
var
  i: integer;
  tmpstr: string;
begin
  tmpstr := '';
  if (DataSet.FieldByName('lfdnr').value <> NULL) and (DataSet.FieldByName('lfdnr').Asinteger <> 0) then
  begin
    qartikelbz.open;
    qartikelbz.Filter := '(lfdnr = ' + DataSet.FieldByName('lfdnr').AsString + ')';
    qartikelbz.filtered := true;
    for i := 0 to qartikelbz.filterrecordcount - 1 do begin
      tmpstr := tmpstr + '+' + qartikelbz.FieldByName('bztext').AsString;
      qartikelbz.next;
    end;
    DataSet.FieldByName('behandlungszustand').AsString := tmpstr;

    tmpstr := '';
    qartikelnw.open;
    qartikelnw.Filter := '(lfdnr = ' + DataSet.FieldByName('lfdnr').AsString + ')';
    qartikelnw.filtered := true;
    for i := 0 to qartikelnw.filterrecordcount - 1 do begin
      tmpstr := tmpstr + qartikelnw.FieldByName('nachweisetext').AsString + ', ';
      qartikelnw.next;
    end;
    i := length(tmpstr);
    if (tmpstr <> '') and (tmpstr[i-1] = ',') then setlength(tmpstr,i - 2);
    DataSet.FieldByName('nachweise').AsString := tmpstr;
  end;  
end;
Zum Anschluss noch eine auswertung die DBIsam mir ausspuckt wenn ich das Query Ausführe:
Zitat:

================================================== ==============================
SQL statement (Executed with 4.26 Build 3)
================================================== ==============================

SELECT *
FROM artikel AS A LEFT OUTER JOIN bestellungenpos AS B ON A.lfdnr = B.artikel
ORDER BY lfdnr DESC

Tables Involved
---------------

artikel (A) table opened shared, has 1094 rows
bestellungenpos (B) table opened shared, has 251 rows

Result Set Generation
---------------------

Result set will be canned

Result set will consist of one or more rows

Result set will be ordered by the following column(s) using a case-sensitive
temporary index:

lfdnr DESC

Join Ordering
-------------

The driver table is the artikel table (A)

The artikel table (A) is joined to the bestellungenpos table (B) with the LEFT
OUTER JOIN expression:

A.lfdnr = B.artikel

Optimizer will attempt to re-order the joins to a more optimal order
Use the NOJOINOPTIMIZE clause at the end of the SQL statement to force the
optimizer to leave the joins in their declared order

The joins are already in optimal order and cannot be optimized any further

Join Execution
--------------

Costs ARE NOT being taken into account when executing this join
Use the JOINOPTIMIZECOSTS clause at the end of the SQL statement to force the
optimizer to consider costs when optimizing this join

The expression:

A.lfdnr = B.artikel

is OPTIMIZED

================================================== ==============================
>>>>> 1112 rows affected in 0,031 seconds
================================================== ==============================
Ich hoffe jemandem fällt was ein, ich bin echt ratlos. Vielen Dank schonmal

Gruß florian

mkinzler 5. Apr 2009 20:25

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
Die Berechnung direkt in der Abfrage durchführen

zack0r 5. Apr 2009 20:30

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
Versteh nich was du meinst. Kannst du vielleicht etwas präziser werden? :)

mkinzler 5. Apr 2009 20:38

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
Ich meinte die temporären Felder direkt in der Abfrage berechnen zu lassen. in deinem fall würde ich aber eigen Abfragen verwenden

zack0r 5. Apr 2009 21:42

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
hmm du meinst SubQuerys oder was? Aber ich kann doch mit SQL keinen String aus den Elementen bauen, oder doch?

mkinzler 5. Apr 2009 21:46

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
Nein als eigene Abfrage. Die Berechnung wird sonst für jede Zeile durchgeführt. Bei 1000 zeilen würde diese dann 1000 mal erfolgen ( wobei er jedes Mal über alle 100 Zeilen gehen würde)
Deshalb eine Abfrage die die Anzahlen der mittlet ( einmalig)

zack0r 5. Apr 2009 22:02

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
hmm ok macht sinn...aber dann kann ich keine Berechneten Felder mehr benutzen oder? Weil die kann ich ja nur in dem OnCalcFields bearbeiten und sonst nicht.

mkinzler 5. Apr 2009 22:08

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
Brauchst du aber auch nicht, weil du auch in einer Abfrage virtuelle Felder erzeugen kannst

zack0r 5. Apr 2009 22:21

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
hmm also ich habs jetz so gemacht: Hab ein neues Query gemacht in dem ich die Felder berechne. Im OnCalcFields von meinem qartikel Query hab ich jetz nur noch diesen code:
Delphi-Quellcode:
  qbznw.Locate('lfdnr', DataSet.FieldByName('lfdnr').AsString, []);
  DataSet.FieldByName('behandlungszustand').AsString := qbznw.FieldByName('behandlungszustaende').AsString;
  DataSet.FieldByName('nachweise').AsString := qbznw.FieldByName('nachweise').AsString;
War das das was du meintest?

Leider ist es aber damit immernoch nicht schneller :(

#EDIT

Also das da oben kann ich mir ja sparen, da ich die Felder ja jetz als Lookup-Felder definieren kann. Das Funktioniert auch. Aber lahm isses immernoch.


GN8 zack0r

mkinzler 6. Apr 2009 05:36

Re: OnCalcFields... gibt es einen effizienteren Weg?
 
Du brauchst keine CalcFelder mehr. Im ersten Schritt Anzahl berechnen, dann die eigentlichen Werte


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:25 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz