Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Daten ohne Zeitverzögerung speichern (https://www.delphipraxis.net/188446-daten-ohne-zeitverzoegerung-speichern.html)

norwegen60 4. Mär 2016 11:46

Datenbank: MsSQL • Version: 2008R2 • Zugriff über: UniDac

Daten ohne Zeitverzögerung speichern
 
Hallo zusammen,

ich habe eine Anwendung in der Timergesteuert (100ms) Messdaten erfasst und in eine DB gespeichert werden. Bei LAN-Zugriff ist das auch ausreichend schnell. Jetzt ist aber ein Rechner nur über WLan verbunden und da habe ich das Problem, dass es manchmal bis zu 2000ms dauert, bis die Daten gespeichert und damit der Timer für den nächsten Prozess freigegeben ist. (Timerereignis ist für Folge-Ereignisse gesperrt bis ein Prozess komplett abgeschlossen ist.)

Ich dachte, dass sich das über
Delphi-Quellcode:
         dmFCalib.dbquQuery.SQL.Text := 'BEGIN TRAN';
          dmFCalib.dbquQuery.SQL.Add('INSERT INTO [Cal_Force] ');
          dmFCalib.dbquQuery.SQL.Add('([CalReportID], [FAct], [FTarget], [Art], [Temperatur], [Humidity], [ServOrt], [ErstUserID], [ErstDat])');
          dmFCalib.dbquQuery.SQL.Add('VALUES');
          dmFCalib.dbquQuery.SQL.Add('(:pCalReportID, :pFAct, :pFTarget, :pArt, :pTemperatur, :pHumidity, :pServOrt, :pErstUserID, GETDATE())');
          dmFCalib.dbquQuery.SQL.Add('COMMIT TRAN');

          // set query parameters
          dmFCalib.dbquQuery.ParamByName('pCalReportID').Value := dmFCalib.dbquCalReport.FieldByName('ID').AsInteger;
          dmFCalib.dbquQuery.ParamByName('pFAct').Value       := rForce;
          dmFCalib.dbquQuery.ParamByName('pFTarget').Value    := rFtarget;
          dmFCalib.dbquQuery.ParamByName('pArt').Value        := cArt;
          dmFCalib.dbquQuery.ParamByName('pTemperatur').Value := uHilfs1.Valreal(edTemperatur.Text);
          dmFCalib.dbquQuery.ParamByName('pHumidity').Value   := uHilfs1.ValReal(edHumidity.Text);
          dmFCalib.dbquQuery.ParamByName('pServOrt').Value    := cServOrt;
          dmFCalib.dbquQuery.ParamByName('pErstUserID').Value := intUser.User.ID;

          dmFCalib.dbquQuery.ExecSQL;
bessert. Die durchschnittliche Zeit für die Ausführung dieses Blocks sinkt auch von 12ms auf 5ms und die Aussetzer sind auch reduziert, aber es gibt sie immer noch.

Wie bekomme ich es hin, dass das Wegschreiben der Daten den Prozess gar nicht beeinflusst. Bei der Verwendung von Threads zusammen mit Datenbankverbindungen habe ich schon die tollsten Sachen gelesen und da ich mit Threading noch nicht vertiefend befasst habe, wäre ich froh, wenn ich hier ein Beispielthread bekommen würde.

Das direkte Wegschreiben der Daten hat den großen Vorteil, dass an einem anderen Arbeitsplatz die Daten mehr oder weniger online beobachtet werden könne

Vielen Dank
Gerd

p80286 4. Mär 2016 11:57

AW: Daten ohne Zeitverzögerung speichern
 
Am einfachsten wäre wohl ein FiFo-Stack, der das Bindeglied zwischen Lesen und Wegschreiben bildet.

Gruß
K-H

Mavarik 4. Mär 2016 11:57

AW: Daten ohne Zeitverzögerung speichern
 
Ist Deine Delphi Version wie im Profil angegeben XE?

Mavarik

AndyDF 4. Mär 2016 11:57

AW: Daten ohne Zeitverzögerung speichern
 
Hallo Gerd,

also ich schreibe und lese permanent Daten aus der Datenbank innerhalb eines Thread. Das funktioniert super, wenn man auf ein paar Dinge achtet.
Wichtig ist, dass alles, was zu dem jeweiligen Schreib- bzw. Lesevorgang gehört, nur von einem Thread verwendet wird. (Connection, Transaction, Query, ..). Also am Besten gleich die gesamte DB Verbindung innerhalb des Threads erzeugen und wieder verwerfen.

Viele Grüße, Andreas

norwegen60 4. Mär 2016 12:23

AW: Daten ohne Zeitverzögerung speichern
 
Hallo,

Delphi Version ist XE3

Was ist mit den Hinweisen, dass innerhalb einer Anwendug keine zwei Connections auf die DB gemacht werden sollen. Wenn der Thraed seine eigene bekommt, sind es bei mir zwei. Das Program ist noch altherkömmlich mit DB-Eingabefeldern programmiert.

Hättest du Code wie der Thraed aussehen müsste. Wie gesagt habe ich mich mit denen noch nicht vertiefend befasst

Danke
Gerd

Sir Rufo 4. Mär 2016 13:12

AW: Daten ohne Zeitverzögerung speichern
 
Wenn die DB einen Multi-User-Zugriff verkraftet, dann kannst du so viele Connections zu der aufbauen, wie du am DB-System zugelassen hast.

Jede Connection sollte aber nur innerhalb eines Thread-Kontexts gleichzeitig verwendet werden, weil man sich sonst mit den Transaktionen verheddert.

Eine Queue ist da schon das Mittel der Wahl ... allerdings solltest du dir etwas überlegen, was du machst, wenn sich die Daten extrem stauen. Wenn du alle 100ms einen Datensatz erzeugst und alle ca. 1000ms zum Schreiben eines Datensatz benötigst, dann kann man sich die Zeit ausrechnen, wann der Speicher nicht mehr ausreicht. Dann muss man entweder Daten auslassen oder zwischenspeichern (Datei, lokale DB, ...).

jobo 4. Mär 2016 13:29

AW: Daten ohne Zeitverzögerung speichern
 
Ich weiß nicht, ob das komponentenspezifisch ist, aber gefühlt gibt es in der Kommunikation viel Overhead/Kleinkram, sagen wir mal, das läuft recht geschwätzig und das tut dann spätestens im WLAN weh, Unidac habe ich aber noch nie benutzt.

Multithreading macht das nicht unbedingt besser, weil gleiche Zugriffs-Technik, es läuft nur asynchron.
Ich würde daher vielleicht versuchen, die einzelnen Queries mit mehr Daten zu beladen, bei einem Query gleicher Overhead, aber mehr "Nutzlast". Dafür müsste man allerdings auf Parametrierung verzichten. Soweit ich weiß kann SQL Server anonyme Blöcke. Das ergäbe soetwas in der Art in einer Query:
Code:
begin
insert into mytable [feldliste*] values (werteliste);
insert into mytable [feldliste*] values (werteliste);
insert into mytable [feldliste*] values (werteliste);
..
end
oder sogar- glaub sql server kann das
Code:
begin
insert into mytable [feldliste*] values ((werteliste);
                                         (werteliste);
                                         (werteliste));
..
end
* feldliste kann man aus Platzgründen vlt auch weglassen, wenn vollständige Werteliste da ist und sichergestellt, dass es zusammenpasst.

Ich könnte mir vorstellen, dass einzelne Queries mit 5, 10 -50 Sätzen ähnlich schnell verarbeitet werden, wie ein einzelner Satz jetzt bei Dir.

Serverseitig könnte man ggF. noch prüfen, ob die Tabellenstruktur für schnelle inserts geeignet ist (wenig/kein Index, ..)

hoika 4. Mär 2016 16:01

AW: Daten ohne Zeitverzögerung speichern
 
Hallo,
du erzeugst die Query ja jedes mal neu auf dem Server.
Probiere doch mal eine prepared Query aus.

Beim Start ds Programmes machst du dein

Delphi-Quellcode:
dmFCalib.dbquQuery.SQL.Text := 'BEGIN TRAN';
dmFCalib.dbquQuery.SQL.Add('INSERT INTO [Cal_Force] ');
dmFCalib.dbquQuery.SQL.Add('([CalReportID], [FAct], [FTarget], [Art], [Temperatur], [Humidity], [ServOrt], [ErstUserID], [ErstDat])');
dmFCalib.dbquQuery.SQL.Add('VALUES');
dmFCalib.dbquQuery.SQL.Add('(:pCalReportID, :pFAct, :pFTarget, :pArt, :pTemperatur, :pHumidity, :pServOrt, :pErstUserID, GETDATE())');
dmFCalib.dbquQuery.SQL.Add('COMMIT TRAN');
zusätzlich kommt dahinter ein
Delphi-Quellcode:
dmFCalib.dbquQuery.Prepared;
Und beim Schreiben der Daten dann nur noch die Parameter füllen

Delphi-Quellcode:
// set query parameters
dmFCalib.dbquQuery.ParamByName('pCalReportID').Value := dmFCalib.dbquCalReport.FieldByName('ID').AsInteger;
dmFCalib.dbquQuery.ParamByName('pFAct').Value := rForce;
dmFCalib.dbquQuery.ParamByName('pFTarget').Value := rFtarget;
dmFCalib.dbquQuery.ParamByName('pArt').Value := cArt;
dmFCalib.dbquQuery.ParamByName('pTemperatur').Value := uHilfs1.Valreal(edTemperatur.Text);
dmFCalib.dbquQuery.ParamByName('pHumidity').Value := uHilfs1.ValReal(edHumidity.Text);
dmFCalib.dbquQuery.ParamByName('pServOrt').Value := cServOrt;
dmFCalib.dbquQuery.ParamByName('pErstUserID').Value := intUser.User.ID;

dmFCalib.dbquQuery.ExecSQL;
Das reduziert die Netzlast.

Schneller wäre dann noch eine stored procedure oder bulk insert.

Die Query dient damit ausschließlich diesem Insert.
Hast du mehr davon -> mehrere Queries benutzen.


Soweit ich nicht erinnere, cacht der sql-server aber parametrisierte Queries selbst,
aber einen Versuch ist es Wert.


Heiko

norwegen60 4. Mär 2016 17:45

AW: Daten ohne Zeitverzögerung speichern
 
Hallo

Zitat:

Zitat von Sir Rufo (Beitrag 1332070)
... allerdings solltest du dir etwas überlegen, was du machst, wenn sich die Daten extrem stauen. ...).

Da habe ich an zwei Möglichkeiten gedacht:
Zuerst werde ich eine gwisse Anzahl zwischenspeichern und wenn zu viele Daten ankommen, werde ich den Zwischenspeicher immer wieder mal löschen. Es ist kein absolutes Muss, dass immer alle Daten gespeichert werden

Zitat:

Zitat von hoika (Beitrag 1332092)
zusätzlich kommt dahinter ein
Delphi-Quellcode:
dmFCalib.dbquQuery.Prepared;

Das kannte ich noch nicht. Werde ich mal probieren. Was passiert hier, wenn ich ExecSQL aufrufe wenn der vorherige Aufruf noch nicht beendet ist?
Wäre so was denkbar:
Delphi-Quellcode:
// set query parameters
if iCount < 10 then
begin
  inc(iCount);
 
  dmFCalib.dbquQuery.ParamByName('pCalReportID').Value := dmFCalib.dbquCalReport.FieldByName('ID').AsInteger;
  dmFCalib.dbquQuery.ParamByName('pFAct').Value := rForce;
  dmFCalib.dbquQuery.ParamByName('pFTarget').Value := rFtarget;
  dmFCalib.dbquQuery.ParamByName('pArt').Value := cArt;
  dmFCalib.dbquQuery.ParamByName('pTemperatur').Value := uHilfs1.Valreal(edTemperatur.Text);
  dmFCalib.dbquQuery.ParamByName('pHumidity').Value := uHilfs1.ValReal(edHumidity.Text);
  dmFCalib.dbquQuery.ParamByName('pServOrt').Value := cServOrt;
  dmFCalib.dbquQuery.ParamByName('pErstUserID').Value := intUser.User.ID;

  dmFCalib.dbquQuery.ExecSQL;
  dec(iCount);
end;
Hat noch jemand einen Ansatz(Code) für den Thread incl. Connection?

Danke
Gerd

hoika 4. Mär 2016 20:59

AW: Daten ohne Zeitverzögerung speichern
 
Hallo,

< Was passiert hier, wenn ich ExecSQL aufrufe wenn der vorherige Aufruf noch nicht beendet ist? >

Wie soll das passieren, der Thread führt seinen eigenen Code Zeile für Zeile nacheinander aus,
aber halt parallel zum Haupt-Thread.


Heiko


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

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