AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Delphi Denkanstoß MemTable/Cachetable FireDac
Thema durchsuchen
Ansicht
Themen-Optionen

Denkanstoß MemTable/Cachetable FireDac

Ein Thema von Eppos · begonnen am 1. Okt 2020 · letzter Beitrag vom 2. Okt 2020
Antwort Antwort
Seite 1 von 2  1 2      
Eppos

Registriert seit: 7. Aug 2006
Ort: Heilbronn
523 Beiträge
 
Delphi 11 Alexandria
 
#1

Denkanstoß MemTable/Cachetable FireDac

  Alt 1. Okt 2020, 11:32
Datenbank: Firebird • Version: 2.8 • Zugriff über: FireDAC
Hallo zusammen,

ich brauche mal einen Denkanstoß.
Ich habe eine Tabelle in der ich variable Zeiträume speicher (Datum von/Bis) und auf die ich mehrmals im System darauf Zugreife um die jeweilige ID des Zeitraumes zu ermitteln. Hier bei bin ich auf die Idee gekommen, bei Systemstart eine FDQuery abzusetzen und diesen im Speicher offen zu lassen, bis ich entweder Refreshe oder das System beende.
Ich Frage mich, ob mehrere Verbindungen zur Datenbank offen zu halten, eine sinnvolle Option ist oder ob dafür eine andere Möglichkeit gibt.
Wie gestaltet es sich, wenn ein anderer User neue Einträge hinzufügt, wie bekommt der Client diese Aktualisierung mit?

Vielen Dank

Eppos
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.080 Beiträge
 
Delphi 12 Athens
 
#2

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 1. Okt 2020, 13:07
Brauchst ja nur eine Verbindung (Connection).

Schade ist, dass bei vielen DB-Komponenten die Daten entladen werden, wenn die Verbindung getrennt wurde. (z.B. Netzwerkproblemchen)
Gut, im AfterConnect/Reconnect der Connection könnte man die Cache-Queries alle wieder öffnen.

Man kann aber auch eine Abfrage machen und dann die Daten umkopieren, in eine MemTable/ClientDataSet, aber wenn man schon kopiert, dann wohl eher direkt in ein TDictionary<> oder eine TObjectList<TMyData> bzw. TList<TMyDataRecord>.


Tja, für Updates brauchst du von der DB irgendwelche Notifications (manchmal auch Alert/Alerter genannt).
Man könnte auch parallel Notifications via TCP/IP oder Sonstwas verteilen, die jeder Client verschickt, wenn er Änderungen macht,
aber wenn die DB es über einen Trigger macht, isses einfacher und vorallem sicherer.
https://www.firebirdsql.org/file/doc...ird_events.pdf
https://mikejustin.wordpress.com/201...ed-middleware/
http://docwiki.appmethod.com/appmeth...lerts_(FireDAC)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 1. Okt 2020 um 13:12 Uhr)
  Mit Zitat antworten Zitat
Blackpit

Registriert seit: 27. Feb 2019
77 Beiträge
 
#3

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 1. Okt 2020, 19:17
... aber wenn man schon kopiert, dann wohl eher direkt in ein TDictionary<> oder eine TObjectList<TMyData> bzw. TList<TMyDataRecord>.
...
Könntest du mir das kurz erläutern, evtl. mit Beispiel, wie du das meinst?
Also in Verbindung mit einem Memtable.

Gruß
BP
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.490 Beiträge
 
Delphi 7 Professional
 
#4

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 1. Okt 2020, 19:35
Hallo zusammen,

ich brauche mal einen Denkanstoß.
Ich habe eine Tabelle in der ich variable Zeiträume speicher (Datum von/Bis) und auf die ich mehrmals im System darauf Zugreife um die jeweilige ID des Zeitraumes zu ermitteln. Hier bei bin ich auf die Idee gekommen, bei Systemstart eine FDQuery abzusetzen und diesen im Speicher offen zu lassen, bis ich entweder Refreshe oder das System beende.
Ich Frage mich, ob mehrere Verbindungen zur Datenbank offen zu halten, eine sinnvolle Option ist oder ob dafür eine andere Möglichkeit gibt.
Wie gestaltet es sich, wenn ein anderer User neue Einträge hinzufügt, wie bekommt der Client diese Aktualisierung mit?

Vielen Dank

Eppos
Über eine Verbindung kann man dutzende von Tabellen und / oder Querys öffnen und mit ihnen arbeiten. Die Frage nach mehreren offenen Verbindungen stellt sich daher nicht. Und selbst wenn: Natürlich kann man mehrere offenen Verbindungen in 'nem Programm haben, egal ob die alle zur gleichen Datenbank gehen oder zu verschiedenen Datenbanken, auch unterschiedlichster Datenbanktypen auf einem oder mehreren Servern.

Die Frage die sich für mich stellt ist: Du willst eine ID haben. Ist die immer gleich oder ändert die sich mit jedem Neuerstellen der Abfrage?

Ist die Ergebnismenge der Abfrage immer gleich, dann leg dir 'ne entsprechende Tabelle in der Datenbank an und greife darauf zu, anstatt bei jedem Programmstart immerwieder die gleiche Ergebnismenge zur Verarbeitung zu erstellen und für die Programmlaufzeit vorzuhalten.

Und 'ne Query kann man beim Porgrammstart öffnen und bis zum Programmende geöffnet halten. Wenn die Menge der Daten nicht exorbitant hoch ist, also in den Arbeitsspeicher passt (ohne andere Programm negativ zu beeinflussen) dann hast Du damit letztlich eh schon 'ne Memorytable, mit entsprechend kurzen Zugriffzeiten. Zumindest klappt das bei mir mit meinem ollen Delphi 7 und Firebird 3 hervorragend. Gezielte Abfragen per SQL auf konkrete Daten (was bei dem Suchen einer ID für ein Zeitinterval ja wohl gegeben sein dürfte) gehen so schnell, dass man das eigentlich nicht merkt.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.080 Beiträge
 
Delphi 12 Athens
 
#5

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 1. Okt 2020, 19:46
Wie gesagt, einfach die Daten (Records und Fields) in ein DataSet ohne DB-Verbindung (MemTable) kopieren.
Delphi-Quellcode:
Q := Datamodule.OpenSql('SELECT a, b FROM t');
try
  MemData.Close; // um den Inhalt schnell zu löschen, oder eben via "while MemData.RecordCount > 0 do MemData.Delete;" jeden Datensatz entfernen
  MemData.Open; // in MemData sind natürlich die gleichen Felder drin, wie im Query
  // eventuell auch noch MemData.DisableControls und MemData.EnableControls verwenden
  while not Q.EoF do begin
    MemData.Insert;

    //TDatamodule.CopyAllFields(Q, MemData); // Wir haben uns ein paar Hilfsfunktionen gebaut, aber man kann auch direkt mir den Query-Komponenten arbeiten.
    for i := 0 to Q.FieldCount - 1 do
      MemData.Fields[i].Value := Q.Fields[i].Value;
    { oder, weil ich unten auch nur zwei Felder nutze
    MemData.FieldByName['a'].Value := Q.FieldByName['a'].Value;
    MemData.FieldByName['b'].Value := Q.FieldByName['b'].Value;
    }


    MemData.Post;
    Q.Next;
  end;
finally
  Q.Free;
end;

Delphi-Quellcode:
//CacheList := TDirectory<string,string>.Create;

with Datamodule.OpenSql('SELECT a, b FROM t') do
  try
    CacheList.Clear;
    while not EoF do begin
      CacheList[AsString('a')] := AsString('b'); // bzw. FieldByName('a').AsString
      Next;
    end;
  finally
    Free;
  end;
Also Daten abrufen (SELECT), die Dataset-Records durchlaufen und die Daten in der Liste speichern.

Und dann nur noch die Liste befragen
Delphi-Quellcode:
S := CacheList['irgendwas']; // Peng, wenn es 'irgendwas' nicht gibt. (könnte man aber auch auf "Leerstring wenn nicht vorhanden" umbauen)

if CacheList.Contains('irgendwas') then
  S := CacheList['irgendwas'];
  
if CacheList.TryGet('irgendwas', X) then
  S := X;

...
und wenn nötig den oberen Code nochmal ausführen, um die Liste zu aktualisieren.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 1. Okt 2020 um 19:52 Uhr)
  Mit Zitat antworten Zitat
Eppos

Registriert seit: 7. Aug 2006
Ort: Heilbronn
523 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 2. Okt 2020, 09:24
@Delphi.Narium
Die Frage die sich für mich stellt ist: Du willst eine ID haben. Ist die immer gleich oder ändert die sich mit jedem Neuerstellen der Abfrage?

Die ist nicht immer gleich, konkret geht es um Geschäftsjahre:
Beispiel 01.01.2020 - 31.12.2020. Jetzt wird anhand des Datums geschaut in welches Geschäftsjahr dies fliest und ob das Geschäftsjahr/der Monat freigegeben ist oder nicht.
Ich hatte mir folgenden Plan ausgedacht: Abfrage bei Systemstart auf die Tabelle. Wenn ich die Abfrage benutze, zuerst ein Reopen (könnte ja sein, dass sich was geändert hat).
Dann per Locate drauf zugreifen.
Was aber vermutlich nicht geht, Locate mit ">= Datum_Von", "<= Datum_Bis"? Hat jemand eine Idee?
  Mit Zitat antworten Zitat
Delphi.Narium

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

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 2. Okt 2020, 10:21
Die ID für den Zeitraum 01.01.2020 - 31.12.2020 ist doch wohl schon immer gleich?

Wie oft musst Du denn auf diese Daten zugreifen: andauernd, permanent (also quasi sekündlich oder öfter) oder eher sporadisch (also eher: Immer dann, wenn ein User einen Geschäftvorfall bearbeitet, was halt eher mal ein paar Minuten länger dauert)?

Im zweiten Fall einfach bei Bedarf das Select absetzen und nachschauen. Dafür lohnt es sich nicht, die Daten permanent vorzuhalten und sie sind dann garantiert immer aktuell.

Wenn Du
Zitat:
Wenn ich die Abfrage benutze, zuerst ein Reopen (könnte ja sein, dass sich was geändert hat).
Dann per Locate drauf zugreifen.
es so machst, wofür der Aufwand einer MemoryTable. Du hast die Daten doch dann sowieso schon in 'ner Query.

Statt Locate gibt es auch noch Filter.

Datenmenge?

Nicht besonders groß (ein paar hundert Sätze dürfen es schon sein)?
Delphi-Quellcode:
  Query.Filtered := false;
  Query.Filter := Format('DatumVon = %s and DatumBis = %s',[QuotedStr(Var_DatumVon),QuotedStr(Var_DatumBis)]);
  Query.Filtered := true;

// oder

  Query.Filtered := false;
  Query.Filter := Format('DatumVon = %d and DatumBis = %d',[2020,2021]);
  Query.Filtered := true;
Wenn Du für jeden Zeitraum genau einen Datensatz hast, stehst Du sofort dadrauf und brauchst nicht weitersuchen. Sind für einen Zeitraum mehrere Datensätze möglich, so musst Du die "Restmenge" durchgehen oder halt den Filter entsprechend erweitern, um als Ergebnis nur einen Datensatz zu erhalten. Ist die Filtermenge leer, dann gibt es das Gesuchte halt nicht.

Im Filter kann man (fast) alles nutzen, was man im Where des SQLs auch "anstellen" kann, solange es um Bedingungen wie = >= <= <> and or geht. (Weitergehendes, wenn nötig, probieren.)

Beim Filter selbst muss Du mal ausprobieren, welcher Datentyp von Seiten Delphis und der DB am besten für Deinen konkreten Fall geeignet ist. Prinzipiell sollte es aber so gehen.

Filter und Filtered gibt es ab TDBDataset. Alles, was davon abgeleitet ist, sollte diese Funktionalität aufweisen.
  Mit Zitat antworten Zitat
Eppos

Registriert seit: 7. Aug 2006
Ort: Heilbronn
523 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 2. Okt 2020, 10:35
Vielen Dank für die ausführliche Beschreibung. Das mit dem Filter werde ich ausprobieren.

Der Zugriff erfolgt während einer Sekunde ca. 10 mal. Aber nur ein paar mal am Tag. Dies für eine Dauer von 5 Minuten. (Prüfprogramm)
Von der memoryTable bin ich weggegangen und hin zu einem DataSet welchen ich vorhalte.

Die ID für einen Zeitraum ist gleich jedoch kann sich innerhalb dieses Zeitraum Tages/Monatsbeschränkungen ergeben die es nicht erlauben den Datensatz zu verarbeiten.
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.388 Beiträge
 
Delphi 12 Athens
 
#9

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 2. Okt 2020, 10:39
Zitat:
Das mit dem Filter werde ich ausprobieren.
...du weißt, daß alle Daten geladen werden und dann die Filterung am Client passiert?
Beispiel:
In der Datenbank sind 10000 Datensätze. Du willst nur die 10 Datensätze haben vom/bis. Die kriegst du dann auch angezeigt. Trotzden wurden alle 10000 geladen.
Besser eine Query mit den Kriterien...und es kommen nur 10 Datensätze.
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.490 Beiträge
 
Delphi 7 Professional
 
#10

AW: Denkanstoß MemTable/Cachetable FireDac

  Alt 2. Okt 2020, 10:58
Wenn ein Prüfprogramm, dann muss kein User "endloslange" warten und kann nicht meckern.

Wäre es denn schlimm, wenn aus den 10 mal pro Sekunde ein 9,5 mal pro Sekunde wird und aus den ca. 5 Minuten ein ca. 5 Minuten und 3 Sekunden?

Probier' doch einfach erstmal aus, ob es nicht sinnvoller ist, die Daten konkret bei Bedarf per SQL abzufragen. Wenn bei FireBird eine Abfrage (mit sehr ähnlicher Wherebedingung) sehr oft hintereinander genutzt wird, ist das "Zeugs" eh noch im Cache, im Speicher und (nach meiner Erfahrung) affig schnell.

Es wäre also erstmal zu prüfen, ob das, was Du vorhast, aus Performanzgründen überhaupt erforderlich ist. Wenn Du Pech hast, dauert die MemoryTable und der Einleseaufwand, oder das Setzen und Nutzen der Filter insgesamt länger, als die (vermuteten) 3000 Abfragen (10 * pro Sekunde * 60 Sekunden pro Minute * 5 Minuten).

@haentschman

Du weißt, dass er vorhatte alle Daten in den Arbeitsspeicher (eine MemoryTable zu laden). Und jetzt sag mir nicht, dass die dann nicht im Arbeitsspeicher liegen. Wir tauschen also hier gerade Arbeitsspeicher gegen Arbeitsspeicher?
Hast Du dafür jetzt eine sinnvolle Begründung, warum die Daten in 'ner Memorytable, 'nem TDirectory im Arbeitsspeicher sinnvoll sein könnten, in 'ner Query aber nicht?

Und ich schrieb: Sinnvoll bei ein paar 100 Sätzen. Also: Wenig. Bei 10000den oder gar Millionen ist es natürlich absoluter Humbug mit Filtern zu arbeiten. Dann ist aber auch ein Locate völlig daneben und 'ne Memorytable und ein TDirectory ebenso.

Ein Problem bei vielen Programmieren ist leider, dass sie die Leistungsfähigkeit von modernen Datenbanksystemen gnadenlos unterschätzen und deshalb mit viel Aufwand im Programm das nachbauen, was sie von der Datenbank selbst mit 'nem einfachen select mal eben performant geliefert bekommt.

Geändert von Delphi.Narium ( 2. Okt 2020 um 10:59 Uhr) Grund: Schreibfehler
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:14 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