Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Einzelne Daten aus Firebird lesen (https://www.delphipraxis.net/100277-einzelne-daten-aus-firebird-lesen.html)

Jens Schumann 25. Sep 2007 16:29

Datenbank: Firebird • Version: 2 • Zugriff über: IBX

Einzelne Daten aus Firebird lesen
 
Hallo,
wie in diesem Thread beschrieben greife ich über eine
ins Excel importierte DLL auf eine Firebird Datenbank zu. Es funktioniert auch einwandfrei. Ich schreibe eine
Formel in die Excelzelle und die Funktion holt den Wert aus der Datenbank. D.h. aber auch, dass für jede einzelne
Zelle ein Wert aus der Datenbank geholt wird. Dafür wird z.Z. für jeden Wert der Abfrageprozess durchlaufen.
- Transaktion starten
- Abfrageparameter setzen
- Dataset öffnen
- Wert holen
- Dataset schließen
- Transaktion schließen

Delphi-Quellcode:
function TPMValue1(Year, Partner, Entity, Posnr, Bwa : PChar) : Double; stdcall;
begin
  Result:=0;
  With DModule do
    begin
      If Not Transaction.Active then
        Transaction.StartTransaction;
      Dataset.SelectSQL.Text:=sqlTpmValue1;
      Dataset.ParamByName('Jahr').AsString:=String(Year);
      Dataset.ParamByName('Partner').AsString:=String(Partner);
      Dataset.ParamByName('Entity').AsString:=String(Entity);
      Dataset.ParamByName('PosNr').AsString:=String(PosNr);
      Dataset.ParamByName('Bwa').AsString:=String(Bwa);
    Try
      Dataset.Open;
      Result:=Dataset.FieldByName('DEZ').AsFloat;
    Finally
      Dataset.Close;
      Transaction.Commit;
      end;
    end; //  With DModule do
end;
Das dauert bei 1000 und mehr Werten ziemlich lange.
Weiss jemand wie ich das Beschleunigen kann.

Hinweis: Alle Werte in eine Abfrage packen und die Excelzellen über ein Routine füllen habe ich schon. Geht ziemlich schnell.
Auch bei über 1000 Werten. Ich möchte aber explizit den Weg über die Excelzellenformel gehen.

mkinzler 25. Sep 2007 16:39

Re: Einzelne Daten aus Firebird lesen
 
Du könntest eine persistente Verbindung verwenden und die Inserts von der Transaktion trennen

Jens Schumann 27. Sep 2007 07:54

Re: Einzelne Daten aus Firebird lesen
 
Hallo mkinzler,
Beispiel: In 5 Zellen steht die Formel.
Bei der ersten Berechnung der ersten dieser 5 Zellen wird von Excel die DLL geladen.
Dabei wird die Verbindung zur Datenbank aufgebaut. Die Verbindung bleibt bis zum Entladen
der DLL bestehen.
Damit habe ich doch eine persistene Verbindung?

Als problematisch sehe ich das ständige Starten und Schließen einer Transaktion pro Wert.
Evt. spendiere ich im Excel einen Menüpunkt "Daten aktualisieren". Mit Klick auf diesen
Menüpunkt wird die aktuelle Transaktion geschlossen und wieder geöffnet. Anschließend werden
die Werte neu gerechnet.

Lemmy 27. Sep 2007 11:44

Re: Einzelne Daten aus Firebird lesen
 
Hi,

wie du korrekt vermutest wird viel Zeit beim Öffnen und Schließen der Transaktion verblasen, deshalb wäre da mein erster Ansatzpunkt. Als weiteren Punkt würde sich anbieten den Select in eine StoredProcedure zu verlegen und das ständige Parsen durch den SQL-Server zu sparen, was bei vielen WErten wieder Geschwindigkeit kostet.

Die Alternative über eine Schleife die 1000 Zellen zu füllen würde mir im Moment als beste Lösung einfallen (da sparst Du dir immer die Transaction zu öffnen/schließen sowie das parsen der SQL, weil Du die nur einmal ausführst...

Grüße
Lemmy

shmia 27. Sep 2007 12:11

Re: Einzelne Daten aus Firebird lesen
 
Du brauchst keine Transaktion, da du nur lesend zugreifst.
Du solltest nicht jede Zelle einzeln holen, sondern alle auf einen Rutsch.
Dazu muss der Rückgabewert von Double zu Variant geändert werden.
Genauer gesagt du musst die Daten in einem 2-dimensionalen Variant-Array verpacken.
Wenn du in Excel dann ein Range-Objekt hast, dass die gleiche Anzahl von Reihen und Spalten hat, kann man das Varaint-Array direkt zuweisen. (rangeobj.Value := variantarray;)
Natürlich ist es nicht ganz einfach Variant-Arrays aus DLLs rauszutransportieren (wer legt es an, wer gibt es frei ?).

TBx 27. Sep 2007 12:54

Re: Einzelne Daten aus Firebird lesen
 
Zitat:

Zitat von shmia
Du brauchst keine Transaktion, da du nur lesend zugreifst.

Hier muss ich doch mal protestieren.
Grundsätzlich wird bei Firebird/Interbase jede Datenoperation (auch Lesen) in einem Transactionskontext durchgeführt.
Bei vielen Komponenten muss man sich nur nicht selbst darum kümmern, weil die das dann selbst erledigen.

Ich gehe mal davon ais, dass Du Deine DLL mit einem Init versehen hast, welches die Connection zur Datenbank herstellt.
Komm jetzt bitte nicht auf die Idee, im gleichen Zuge eine Transaction zu öffnen, die dann die ganze Zeit durchgängig genutzt wird. Damit blockierst Du Dir dann nämlich Deinen Datenbankserver (Stichwort Oldest Active Transaction).

Zitat:

Zitat von Jens Schumann
Ich möchte aber explizit den Weg über die Excelzellenformel gehen.

Ich fürchte, dann bleibt Dir die geringe Geschwindigkeit erhalten :-(

Gruß

Thomas

Jens Schumann 27. Sep 2007 13:33

Re: Einzelne Daten aus Firebird lesen
 
Zitat:

Zitat von shmia
Genauer gesagt du musst die Daten in einem 2-dimensionalen Variant-Array verpacken.
Wenn du in Excel dann ein Range-Objekt hast, dass die gleiche Anzahl von Reihen und Spalten hat, kann man das Varaint-Array direkt zuweisen. (rangeobj.Value := variantarray;)
Natürlich ist es nicht ganz einfach Variant-Arrays aus DLLs rauszutransportieren (wer legt es an, wer gibt es frei ?).

Die Lösung habe ich schon realisiert. Das eignet sich hervorragend wenn man mehrere Werte aus der Datenbank holen will.
Ich möchte aber einen Wert aus der Datenbank holen und innerhalb einer Excelformel verwenden. Das ist der Unterschied.

Jens Schumann 27. Sep 2007 13:38

Re: Einzelne Daten aus Firebird lesen
 
Zitat:

Zitat von onlinekater
Ich gehe mal davon ais, dass Du Deine DLL mit einem Init versehen hast, welches die Connection zur Datenbank herstellt.
Komm jetzt bitte nicht auf die Idee, im gleichen Zuge eine Transaction zu öffnen, die dann die ganze Zeit durchgängig genutzt wird. Damit blockierst Du Dir dann nämlich Deinen Datenbankserver (Stichwort Oldest Active Transaction).

Das habe ich natürlich nicht gemacht. Deshalb öffne ich ja z.Z. bei jeder Abfrage eine Transaktion.
Mein Ansatz ist jetzt folgender:
- Starte tatsächlich beim Laden der DLL eine Transaktion.
- Biete einen Menüpunkt an, der es ermöglich die laufende Transaktion zu beenden und eine neue zu starten.
Anschließend wird das Tabellenblatt neu berechnet. (Dann sind auch die aktuellen Daten da)
- Schließe die Transaktion beim Entladen der DLL


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:09 Uhr.

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