Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Optimierung Datenbankzugriff Firebird (https://www.delphipraxis.net/174674-optimierung-datenbankzugriff-firebird.html)

Perlsau 5. Mai 2013 00:53

Optimierung Datenbankzugriff Firebird
 
Moin allerseits,

ich greife mit den IBDac-Komponenten auf eine Firebird-Datenbank zu, in der bereits 16 Tabellen existieren. Beim Verbinden mit den Tabellen vergehen knapp 8 Sekunden, und mir kommt das doch ein wenig lang vor. Zum Projekt:

Auf einem Datenmodul sitzen eine TIBCConnection, 16 TIBCTable mit den dazugehörenden TIBCDataSource und zwei TIBCTransaction. In OnShow der Hauptform rufe ich meine Verbindungs-Funktion auf:
Delphi-Quellcode:
function TDatMod.Verbinden_Datenbank : Boolean;
begin
   Trennen_Datenbank;

   ConMain.Username          := Adr_Types.URec.DB_User;
   ConMain.Password          := Adr_Types.URec.DB_Pass;
   ConMain.Options.Role      := Adr_Types.URec.DB_Role;
   ConMain.Server            := 'localhost';
   ConMain.SQLDialect        := 3;
   ConMain.LoginPrompt       := False;
   ConMain.Options.Charset   := 'UTF8';
   ConMain.Options.UseUnicode := True;

   IF Adr_Types.DB_Embedded THEN
   BEGIN
        ConMain.ClientLibrary := Adr_Types.URec.Pfad_Main + Adr_Types.Client_EmbedDLL;
        ConMain.Database     := Adr_Types.URec.Pfad_Main + Adr_Types.DatenbankDateiName;
   END ELSE
   BEGIN
        ConMain.ClientLibrary := Adr_Types.URec.Pfad_Main + Adr_Types.Client_ServerDLL;
        ConMain.Database     := Adr_Types.URec.Pfad_DB  + Adr_Types.DatenbankDateiName;
   END;

   TRY
      ConMain.Connect;
   EXCEPT
      on e:exception DO ShowMessage('Fehler beim Verbinden mit der Datenbank: ' + e.Message);
   END;

   Result := ConMain.Connected;
end;
Das dauert meinen Messungen nach in der IDE im Debug-Mode 141 Millisekunden, dagegen als Exe Release gestartet nur noch 93 ms. Der Verbindungsaufbau zur Datenbank ist also nicht das Problem, wie ich oben schon andeutete. Die 16 TIBCTable-Komponenten auf Active := True zu setzen, dauert:
IDE Debug-Mode 8827 ms,
Exe Release 7155 ms.

Danach kommt das Setzen diverser Einstellungen von Tabellen, Sortierreihenfolgen usw., das dauert:
IDE Debug-Mode 2422 ms,
Exe Release 1828 ms.

Die Tabellen setze ich mit TIBCTable.Open aktiv:
Delphi-Quellcode:
function TDatMod.Verbinden_Tabellen: Boolean;
begin
     Result := False;

     TRY
        Tab_Benutzer.Open;
        Tab_Rechte.Open;
        Tab_Geschlecht.Open;

        ...

        Result := True;
     EXCEPT
        on e:exception DO ShowMessage('Fehler beim Verbinden mit den Tabellen: ' + e.Message);

     END;
end;
Von einem freundlichen Programmiererkollegen mit Win 7 und Radstudio XE2 erhielt ich folgende Testergebnisse, nachdem er mein Projekt auf seinem System getestet hatte:

*** Wie oben Win 7 32 Bit Debug
IF NOT DatMod.Verbinden_Datenbank THEN 70
IF NOT DatMod.Verbinden_Tabellen THEN 5129
Set_Einstellungen; 2327

*** Wie oben Win 7 64 Bit Debug
IF NOT DatMod.Verbinden_Datenbank THEN 58
IF NOT DatMod.Verbinden_Tabellen THEN 3867
Set_Einstellungen; 1847

*** Wie oben Win 7 32 Bit Release
IF NOT DatMod.Verbinden_Datenbank THEN 60
IF NOT DatMod.Verbinden_Tabellen THEN 5076
Set_Einstellungen; 2306

*** Wie oben Win 7 64 Bit Release
IF NOT DatMod.Verbinden_Datenbank THEN 64
IF NOT DatMod.Verbinden_Tabellen THEN 3855
Set_Einstellungen; 1777

*** Wie oben Win 7 32 Bit Debug IDE
IF NOT DatMod.Verbinden_Datenbank THEN 160
IF NOT DatMod.Verbinden_Tabellen THEN 5957
Set_Einstellungen; 2532
DatMod.ZweiteVerbindung; 55

*** Wie oben Win 7 64 Bit Release
IF NOT DatMod.Verbinden_Datenbank THEN 196
IF NOT DatMod.Verbinden_Tabellen THEN 3854
Set_Einstellungen; 1579
DatMod.ZweiteVerbindung; 48


Auf seinem Rechner, der ungefähr dieselbe Taktfrequenz und Ausstattung wie meiner hat (2x3 GHz, 4 GB Speicher) geht es also am schnellsten, wenn er eine 64-Bit-Anwendung erzeugt und mit einer 64-Bit-Firebird-Installation arbeitet. Leider kann ich nur 32-Bit-Anwendungen erzeugen, aber ich glaube, daß man das irgendwie optimieren kann, hab aber im Moment keinen blassen Schimmer, wo ich ansetzen könnte.

Der Eintrag DatMod.ZweiteVerbindung; in den letzten beiden Versuchen beschreibt die Zeit, die eine zweite Verbindung mit nur einer Tabelle benötigt (incl. Datenbankverbindung und Tabellen-Komponente auf aktiv setzen. Bei dieser zweiten Verbindung wurden keine Komponenten aufs Datenmodul geschoben, sondern dieselben im Create des Datenmoduls erst erzeugt:
Delphi-Quellcode:
procedure TDatMod.DataModuleCreate(Sender: TObject);
begin
   ConMainX          := TIBCConnection.Create(DatMod);
   TransMainX        := TIBCTransaction.Create(DatMod);
   Tab_LandX         := TIBCTable.Create(DatMod);
   Dsrc_LandX        := TIBCDataSource.Create(DatMod);
end;
Die Verbindung wird bei dieser Zweitverbindung erst hergestellt, wenn die erste Verbindung bereits besteht:
Delphi-Quellcode:
procedure TDatMod.ZweiteVerbindung;
begin
     ConMainX.Username                    := Adr_Types.URec.DB_User;
     ConMainX.Password                    := Adr_Types.URec.DB_Pass;
     ConMainX.Options.Role                := Adr_Types.URec.DB_Role;
     ConMainX.Server                      := 'localhost';
     ConMainX.SQLDialect                  := 3;
     ConMainX.LoginPrompt                 := False;
     ConMainX.Options.Charset             := 'UTF8';
     ConMainX.Options.UseUnicode          := True;
     ConMainX.ClientLibrary               := Adr_Types.URec.Pfad_Main + Adr_Types.Client_ServerDLL;
     ConMainX.Database                    := Adr_Types.URec.Pfad_DB  + Adr_Types.DatenbankDateiName;
     ConMainX.DefaultTransaction          := TransMainX;
     ConMainX.Connect;
     TransMainX.Active                    := True;
     Tab_LandX.Connection                 := ConMainX;
     Tab_LandX.TableName                  := 'LAND';
     Tab_LandX.KeyGenerator               := 'GEN_LAND_ID';
     Tab_LandX.KeyFields                  := 'IDX_LAND';
     Tab_LandX.IndexFieldNames            := '';
     Tab_LandX.Options.BooleanDomainFields := True;
     Tab_LandX.Open;
     Dsrc_LandX.DataSet := Tab_LandX;
     Dsrc_LandX.Enabled := True;
end;
Wäre es angesichts der Tatsache, daß die Zweitverbindung nur 48 ms inkl. einer Tabelle benötigt, hilfreich, alle Komponenten erst zur Laufzeit zu erzeugen? Ich könnte das ja mühevoll austesten, aber vielleicht hat ja bereits jemand diesen Versuch gemacht.

Was gäbe es sonst noch für Möglichkeiten, die Herstellung der Verbindungen zu beschleunigen?

haentschman 5. Mai 2013 08:18

AW: Optimierung Datenbankzugriff Firebird
 
Moin...

die Lösung ist einfach...
Zitat:

Die 16 TIBCTable-Komponenten auf Active := True zu setzen, dauert:
...Queries benutzen und nur die Daten holen die wirklich benötigt werden. Sollte dann die Datenmenge immer noch zu groß sein bleibt nur ein Fortschrittsbalken oder ein Design überdenken 8-)

mkinzler 5. Mai 2013 08:26

AW: Optimierung Datenbankzugriff Firebird
 
Ich vermute auch, dass es an den beim Öffnen zu ladenenden Datenmengen liegt. Ich bezweifle, dass alle 16 sofort benötigt werden und, wie haentschman schon schrieb, die bei den benötigten Tabellen nicht deren vollständigen Inhalt.

Zudem kannst du auch mit der embedded Dll auf einen Server zugreifen ( dann über IP)

IBExpert 5. Mai 2013 08:29

AW: Optimierung Datenbankzugriff Firebird
 
Moin,

das hängt von verschiedenen Faktoren ab, u.a. deinem Tabellendesign, aber auch generell davon, das du halt TTable Varianten benutzt. Da sind längst nicht alle Komponentenvarianten schnell und die treiben meistens einen Riesen Overhead gegenüber reinen SQL Komponenten, bei denen du bestimmt, welches SQL ausgeführt wird und wann es ausgeführt wird. Wenn du sehr viele Felder in deinen Tabellen hast müssen wesentlich mehr Metadaten geladen werden.

Was Firebird wirklich macht kannnst du z.B. bei FB25 mit der TraceAPI erkennen
http://ibexpert.net/ibe/index.php?n=Doc.TraceAndAudit (geht auch mit der IBExpert Trial, aber nicht mit der Personal, gibt aber auch andere Tools)

Dazu kommt dann noch die von dir benutzte Firebird Version. Wenn es der Superclassic oder classic ist und du anden Cache Buffers nichts geändert hast, dann liegt wohl auch da der Hund begraben. Beim Superserver, den ich für jeden empfehle, der sich weniger mit FB auskennt, der default cache buffer mit 2048 ok, beim classic oder superclassic mit 75 viel zu gering. sehe kannst du den Wert in der Datenbankstatistik oder hier
http://ibexpert.net/ibe/index.php?n=...baseProperties (da kannst du den wert auch höher setzen, Mindestwert 2000, besser 10000).

Ich hab mir die statischen Datenmodule mit hunderten von Komponenten schon vor Jahren abgewöhnt. Bei diversen Delphi Consulting Jobs sehe ich aber noch Datenmodule mit hunderten von Datasets, das ist kaum wartbar, entsteht aber meistens im Laufe der Jahre weil man mal so angefangen hat und nun an zig tausend TField Objekten und TDataset Events was rangebastelt hat, was man nicht mal eben ändern kann. Ich erzeuge alle Datasets zur Laufzeit, aber performancemäßig macht das eigentlich keine Unterschied.

Wenn es geht, dann vermeide generell TTable Varianten, da geht Komfort für den Programmierer zu Lasten Performance für Endanwender.

Evtl. hast du aus der TraceAPI ode rdurch geänderte Cache Buffers ja schon neue Erkenntnisse

arnof 5. Mai 2013 10:03

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von haentschman (Beitrag 1214154)
Moin...

die Lösung ist einfach...
Zitat:

Die 16 TIBCTable-Komponenten auf Active := True zu setzen, dauert:
...Queries benutzen und nur die Daten holen die wirklich benötigt werden. Sollte dann die Datenmenge immer noch zu groß sein bleibt nur ein Fortschrittsbalken oder ein Design überdenken 8-)

wir er schon ngeschrieben hat, mit tables auf active = True, läds Du alle Datenbank inhalte in deinen RAM, das wird immer länger dauern, je mehr Daten Du in der DB hast.....

Schau Dir auch mal im Taskmanager den Ramverbrauch deiner EXE an, da wirst Du sehen je mehr Daten da sind desdo mehr ram verbraucht deine exe.

PS: bei 2 GB ist dann schluß .. bei 32 bit anwendung ....

IBExpert 5. Mai 2013 10:32

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von arnof (Beitrag 1214171)
wir er schon ngeschrieben hat, mit tables auf active = True, läds Du alle Datenbank inhalte in deinen RAM, das wird immer länger dauern, je mehr Daten Du in der DB hast.....

wenn deine TTable Komponente das macht, dann schmeiss die weg, das passiert zwar gerne mal bei clientdatasets oder memorydatasets oder wenn man sinnloserweise einfach mal recordcount abfragt, aber durch active=true auf sinnvoll prgrammierten ttable varianten ist das nicht der Fall.

Perlsau 5. Mai 2013 12:07

AW: Optimierung Datenbankzugriff Firebird
 
@alle: Das sind in er Tat sehr nützliche Tipps und Hinweise, die ihr da parat habt. Es wird echt Zeit, daß ich mich mit all diesen Optimierungsmöglichkeiten eingehender befasse. Immerhin hab ich heute nacht noch bis gegen 4 Uhr herumprobiert und getestet. Ich hab da eine Tabelle, die enthält 10 Felder und derzeit ca. 300.000 Datensätze. Bin noch am Einlesen, am Ende werden es knapp eine Million Datensätze sein, dazu 5 Untertabellen mit jeweils 2 bis 4 Feldern, die auch bis zu 50.000 Datensätze fassen.

Auf die meisten Tabellen werden beim Start Locate-Methoden angewandt, um die zuletzt bearbeiteten Datensätze für den Anwender sofort sichtbar zu machen. Auch das werde ich nochmal überdenken, denn eigentlich benötigt der Anwender nur zwei oder drei Tabellen, mit denen er wirklich ständig arbeitet. Das sollte auch etwas Geschindigkeit beim Start bringen.

In den Options der Tab-Kompos habe ich bereits das Property QueryRecordCount deaktiviert. Das hat die Sache schon mal ein wenig beschleunigt, denn das Durchzählen der Datensätze nimmt natürlich auch Zeit in Anspruch. Ich werde den RecordCount bei den entsprechenden Tabellen in der Anwendung verwalten.

@Holger Klemt & haentschman: Die Table-Komponente von IBdac soll ja laut Dokumentation ein direkter Abkömmling von TCustomIBCQuery sein. Aber ich probier's heute mal aus, problematische Table-Komponenten durch Queries zu ersetzen. Bei den Tabellen für Benutzereinstellungen, Benutzerrechte, Geschlecht und Anrede kann ich mir das schenken, die enthalten nur ein paar Datensätze.

@Holger Klemt: Hab leider nur die Personal-Version von IBExpert. Aber die Database-Properties kann ich mir natürlich anzeigen lassen: Unter Buffer steht Pages auf 90 und KB auf 1440. Hab jetzt mal den Wert auf 10000 kb erhöht, dabei entstehen 625 Seiten und der Sweep-Interval steht auf 20000.

Leider weiß ich nicht mehr genau, welche Firebird-Version (v2.5) ich installiert hatte, aber ich glaube mich zu erinnern, daß es er Classic-Server war. IBexpert schreibt mir das heraus, wenn ich die Servereigenschaften abfrage:
Server Version: WI-V2.5.2.26539 Firebird 2.5
Server Implementation: Firebird/x86/Windows NT
Service Version: 2

Zitat:

Zitat von mkinzler (Beitrag 1214155)
Ich vermute auch, dass es an den beim Öffnen zu ladenenden Datenmengen liegt. Ich bezweifle, dass alle 16 sofort benötigt werden und, wie haentschman schon schrieb, die bei den benötigten Tabellen nicht deren vollständigen Inhalt.

Ich glaube nicht, daß TIBCTable die gesamte Datenmenge in den Speicher lädt. Aber die Tabellen werden schon benötigt, weil sie Untertabellen für die noch fehlende Haupttabelle darstellen, die hauptsächlich aus Feldern der Untertabellen zusammengesetzt sein wird.

Zitat:

Zitat von mkinzler (Beitrag 1214155)
Zudem kannst du auch mit der embedded Dll auf einen Server zugreifen ( dann über IP)

Die Embedded.dll ist aber wesentlich größer als die "normale": 3.801.088 vs 552.960 Bytes. Das muß meiner Ansicht nach nicht sein, für den Zugriff auf den lokalen Firebird-Server die knapp 4 MB große DLL einzusetzen. Diese ist nur dafür gedacht, daß de Anwender sein Programm von einem externen Datenträger, z.B. einem Stick oder einer externen Festplatte, starten möchte. Der Anwender soll in die Lage versetzt werden, bei Bedarf Datenbank und Anwendung zu kopieren und "mitzunehmen".

@alle: Nochmal vielen Dank an euch, ich werde jetzt gleich nach dem verspäteten Frühstück darangehen, eure Vorschläge umzusetzen.

jobo 5. Mai 2013 12:48

AW: Optimierung Datenbankzugriff Firebird
 
Meine Empfehlung wären ebenfalls Queries, die gezielt Teilmengen abrufen.
Mit Table Komponenten habe ich schon lange nicht mehr gearbeiet, gibt es da sowas wie max-records?
Wenn Du bei Tables bleiben musst/willst, probier doch mal Filter auf PK Felder, die garantiert eine leere Menge ergibt (oder eine garantiert kleine~1 Datensatz z.B...
Im weiteren Programmverlauf muss natürlich was sinnvolles in den Filter rein, Hauptsache, die große Tabellen werden nicht/niemals ungefiltert geöffnet und alles wird geladen.

sx2008 5. Mai 2013 13:06

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von IBExpert (Beitrag 1214156)
Ich hab mir die statischen Datenmodule mit hunderten von Komponenten schon vor Jahren abgewöhnt. ... das ist kaum wartbar...
Ich erzeuge alle Datasets zur Laufzeit, aber performancemäßig macht das eigentlich keine Unterschied.

Statische (Query-)Komponenten aus Datenmodulen sind schon in Ordnung solange man es mit der Stückzahl nicht übertreibt.
Die Obergrenze liegt so bei 16 bis 20 Stück.
Es ist wichtig, die Abfragen thematisch auf mehrere Datenmodule zu verteilen und jedes Datenmodul möglichst so zu designen, dass es keine Abhängigkeiten zu anderen Datenmodulen hat.

Du hast ganz richtig erkannt, dass zu viele Datasets auf einem Datenmodul extrem schwer zu warten sind.
Deine Schlussfolgerung in Zukunft ALLE Datasets zur Laufzeit zu erzeugen ist aber auch nicht die Lösung.
Du verschenkst damit Entwicklungszeit und erhöhst die Menge des Sourcecodes.
(je mehr Sourcecode, umso mehr Fehlermöglichkeiten gibt es)

Perlsau 5. Mai 2013 13:11

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von jobo (Beitrag 1214193)
Meine Empfehlung wären ebenfalls Queries, die gezielt Teilmengen abrufen.
Mit Table Komponenten habe ich schon lange nicht mehr gearbeiet, gibt es da sowas wie max-records?
Wenn Du bei Tables bleiben musst/willst, probier doch mal Filter auf PK Felder, die garantiert eine leere Menge ergibt (oder eine garantiert kleine~1 Datensatz z.B...
Im weiteren Programmverlauf muss natürlich was sinnvolles in den Filter rein, Hauptsache, die große Tabellen werden nicht/niemals ungefiltert geöffnet und alles wird geladen.

Ebenso wie TIBCTable fragt TIBCQuery nur die Anzahl an Zeilen aus der zugrundeliegenden DB-Tabelle ab, die im Property FetchRows angegeben ist, das bei mir defaultmäßig auf 25 steht. Nur bei Abfrage von RecordCount, dem Setzen des Properties FetchAll oder/und dem Setzen des Properties QueryRecCount werden alle Datensätze abgefragt, aber außer bei FetchAll nicht im Speicher behalten. Diese drei Properties stehen bei mir alle auf False.

Mit dem Umstellen von TIBCTable auf TIBCQuery habe ich das goldene Los gezogen, die Startzeit hat sich nun merklich verringert:
Code:
IF NOT DatMod.Verbinden_Datenbank THEN   124
IF NOT DatMod.Verbinden_Tabellen THEN     31
Set_Einstellungen;                      2156

IBExpert 5. Mai 2013 14:26

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von sx2008 (Beitrag 1214195)
Deine Schlussfolgerung in Zukunft ALLE Datasets zur Laufzeit zu erzeugen ist aber auch nicht die Lösung.
Du verschenkst damit Entwicklungszeit und erhöhst die Menge des Sourcecodes.
(je mehr Sourcecode, umso mehr Fehlermöglichkeiten gibt es)

Das schöne ist bei meiner Vorgehensweise, das ich kaum Sourcecode habe und schon gar nicht wegen einer neuen Tabelle neuen Source ergänzen muss. Ich hatte mal vor ewigkeiten auf einer Entwicklerkonferenz dafür ein paar Sessions zum Thema OOP gegeben und das Verfahren in den letzten 13 Jahren noch mal deutlich weiterentwickelt. Damals hatte ich durch einen Quelltextgenerator einfach zu jeder Tabelle in der DB eine eigene Unit erzeugt, in der dann eine von einer Basisklasse abgeleitete Klasse erzeugt wurde, die dann sämtliche Datenbankoperationen einheitlich abgewickelt hat und nebenbei auch noch dynamisch passende TWincontrols auf jeden beliebigen Container (TPanel, TScrollbox o.ä.) erzeugen konnte.

Erst auf der Ebene der Basisklasse habe ich dann die konkrete Implementation angesprochen, also ob das TQuery, TIBOQuery, TICQuery oder was auch immer war, solange es eine Dataset Ableitung war. Ich bekomme immer noch Tränen in den Augen, wenn ich sehe, wie viele Kundenprojekte zum Beispiel mal mit IBObjects realisiert wurden und wo man sich in ewige Abhängigkeit davon begeben hat. Wenn ich in einer Unit nur den Konstrutor auf ein andere Klasse portieren muß dauert das ggf. nur wenige Minuten, wenn ich aber in 200 Datenmodulen 5000 Datasetableitungen mit 50000 TField Definitionen anpassen muß, dann sieht das schon ganz anders aus, insbesondere wenn es auf einmal gewisse TFieldklassen, -properties oder events gar nicht mehr pder mit anderer Implementation gibt.

Der Quelltextgenerator selbst hat danach dann auch noch (sofern nicht schon vorhanden) von dieser Klasse noch mal eine Ableitung erstellt, in der ich dann Methoden überschreiben konnte und völlig andere Implemetationen für komplexere Aufgaben umsetzen konnte.

Der Quelltextgenerator hat neben den Objektklassen auch noch automatisch diverse include files erzeugt, die ich dann im eigentlichen Projekt eingebaut habe. Da der meiste Sourcecode aus dem Quelltextgenerator erzeugt wurde war dieser per Definition fehlerfrei. Ob der dann das gemacht hat, was er machen sollte, lag am Sourcecode vom Quelltextgenerator, aber in einem großen Projekt mit ca. 800 Tabellen musste für die Kompatibilitätsschicht zwischen Firebird und IBM AS/400 iSeries (oder wie auch immer die Kiste jetzt heißt) nach einem Update auf der AS/400 Seite und der Umstellung von Delphi/400 auf ODBC ziemlich viel geändert werden. Das wurde aber nur ein einer klasse exemplarisch manuell gemacht, bis es lief und dann der Quelltextgenerator angepasst, damit der die neuen Strukturen erzeugt. Die restlichen 799 Klasse dauerten danach weniger als eine Minute. Der Quelltextgenerator war übrigens eine ganz gruselige Implementation (TForm mit TMemo, TButton, einer TxDatabase, einer TxQuery) und einem endlosen OnClick Event, mit dem die gefundenen Metadaten aus der DB in Delphi kompatiblen Quellcode umgewandelt wurde. Einige werden sich evtl noch dran erinnern ...

Das klassische RAD Prinzip von Delphi ist zwar am Anfang sehr produktiv, aber bei Projekten, die mehrere Jahre auch in größeren Teams entwickelt werden sollen, kann das schon mal gewaltig nach hinten losgehen. Ob man sich mal vor Jahren zum Einsatz von IBObjects entschlossen hat, Orpheus oder Turbopower Krams eingebaut hat oder was auch immer vor einigen Jahren mal angesagt war: Die konkrete Implementation an zigtausend Stellen im eigenen Quellcode lässt sich meistens mit Mühe und Suchen/Ersetzen noch lösen, der ganze Kram in den DFMs ist dann aber oft schon mit dem ersten Öffnen der Formulare mit fehlender oder falschen Komponentenversion hoffnungslos vergurkt.

Ich habe im Laufe der Jahre diverse Softwarehäuser beraten, die oft auch meine Architektur übernommen haben und von denen habe ich viele Rückmeldungen, das dadurch die Fehler der Vergangenheit endlich hinter sich lassen konnten.

Mittlerweile läuft das bei mir ohne eigene Units pro Tabelle über eine im Laufe der Jahre entwickelte Basisklasse, bei der alle Information zu jeder Tabelle bei ersten Zugriff im Client gecacht werden. Für lesen und schreiben der Daten werde eigene SQLs automatisch erzeugt oder, sofern vorhanden, nach bestimmten Namenskonvention vorhandene SPs benutzt.

In meinem Modell ist die Datenbankstruktur Basis für alles andere, ich weiß aber auch, das viele das gerne andersherum lösen. Mein Vorteil ist, das meine Implementation mit völlig unterschiedlichen Datenbanken auch völlig unterschiedliche Anforderungen umsetzen kann, ich also für jeden Kunden individuell customizen kann. Ich glaub bei der Entwicklungszeit kann ich mit anderen Modellen sehr gut mithalten, die grundlegende Basis ist war nicht in 5 Tagen entwickelt, wenn man die dann aber stehen hat, geht es extrem fix.

Mehr Komponenten bedeutet nicht zwangsläufig weniger Quellcode, umgekehrt aber auch nicht. Der ganze Bereich der Programmierung wäre aber auch extrem langweilig, wenn es immer nur die "eine Lösung" geben würde.

IBExpert 5. Mai 2013 14:49

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von Perlsau (Beitrag 1214188)
Auf die meisten Tabellen werden beim Start Locate-Methoden angewandt, um die zuletzt bearbeiteten Datensätze für den Anwender sofort sichtbar zu machen. Auch das werde ich nochmal überdenken, denn eigentlich benötigt der Anwender nur zwei oder drei Tabellen, mit denen er wirklich ständig arbeitet. Das sollte auch etwas Geschindigkeit beim Start bringen.

Locate ist meistens ein blödes Verfahren, weil eben alle Records zum Client geliefert werden, bis derjenige kommt, den du haben wolltest. Das entschidet aber der Client. Ist bei Filterproperties auch oft so ähnlich. Da kannst du auch bei der Auskunft anrufen und dir das Telefonbuch komplett vorlesen lassen. Bei kleinen Datenmengen ist das egal, aber 300000 oder 1000000 Records sind keine kleine Datenmenge mehr.


Zitat:

Zitat von Perlsau (Beitrag 1214188)
Hab leider nur die Personal-Version von IBExpert. Aber die Database-Properties kann ich mir natürlich anzeigen lassen: Unter Buffer steht Pages auf 90 und KB auf 1440. Hab jetzt mal den Wert auf 10000 kb erhöht, dabei entstehen 625 Seiten und der Sweep-Interval steht auf 20000.
...

Leider weiß ich nicht mehr genau, welche Firebird-Version (v2.5) ich installiert hatte, aber ich glaube mich zu erinnern, daß es er Classic-Server war. IBexpert schreibt mir das heraus, wenn ich die Servereigenschaften abfrage:
Server Version: WI-V2.5.2.26539 Firebird 2.5
Server Implementation: Firebird/x86/Windows NT
Service Version: 2

Das sieht also nach Classic aus (oder Superclassic). Trag mal da wo jetzt 625 steht 5000 ein, dann müsste rechts 80000kb stehen (das wären 80 MB cache pro Connection, der Wert wird auch in der DB gespeichert). Wenn du keinen konkreten Grund hast, dann am besten noch mal deinstallieren und als Superserver neu installieren, das hat für jemanden, der nicht im Thema drin ist, meistens Vorteile, weil beim Superserver solange noch mindestens eine Connection geöffnet ist alle Daten im Cache bleiben und jeder Client die Abfragen wenn möglich aus dem Cache beantwortet bekommt. Je langsamer die festplatte, um so größer die Vorteile des Superservers. Beim Classic hat jede Connection immer einen eigenen Cache, das macht nur Sinn bei extrem schnellen Datenträgern, z.B. Enterprise SSDs. Beim Superserver kannst du den Cache auch auf z.B. 20000 setzen. Sweep Interval ist dafür erst mal nicht relevant.

Wenn du noch mehr Infos zu Firebird brauchst und dir mal hier und da Zeit dafür nehmen kannst, dann würde ich mal so nach und nach die Videos auf http://www.youtube.com/user/IBExpertise oder im IBExpertLive Player (http://ibexpert.net/ibe/index.php?n=Doc.IBExpertLive) anschauen, da sind auch einige deutschsprachige Schulungen von uns dabei.

IBExpert 5. Mai 2013 14:54

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von Perlsau (Beitrag 1214188)
Hab leider nur die Personal-Version von IBExpert

kann man ändern, gibt es für facebook likes als Sonderpreis für 99 € :-)
https://www.facebook.com/IBExpertise...51161908249538

tsteinmaurer 5. Mai 2013 19:25

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Locate ist meistens ein blödes Verfahren, weil eben alle Records zum Client geliefert werden, bis derjenige kommt, den du haben wolltest
Um Mißverständnissen vorzubeugen. Das war zu Zeiten der BDE. IBObjects zum Beispiel ist da viel cleverer. IBDac eventuell auch. Ist mit der Trace API nun alles schön transparent, was da von den Zugriffskomponenten teilweise verbrochen wird. Aber das Thema Trace API wurde ja bereits erwähnt ... :thumb:

Perlsau 5. Mai 2013 19:29

Nachtrag zu: Optimierung Datenbankzugriff Firebird
 
Den Übeltäter für die langen Wartezeiten beim Starten meiner Anwendung habe ich jetzt eindeutig ausgemacht: Er heißt Sortieren. Nachdem ich alle Zuweisungen an IndexFieldNames – jenes Property der IBDac-Query-Komponenten, das für die Sortierung zuständig ist – entfernt hatte, warte ich ca 2 Sekunden darauf, daß die Anwendung zur Verfügung steht (ohne Ladezeit, da sind's dann schätzungsweise 3,5 Sekunden, also nur für den Aufbau der Anwendung im Speicher). Sobald ich jedoch sortieren lasse, ist die Geschwindigkeit dahin, ganz besonders bei meiner größten Tabelle mit derzeit um die 300.000 Einträgen und etlichen Abhängigkeiten. Eigentlich wird ja nicht die eigentliche Tabelle sortiert, sondern lediglich das View, das ich von dieser Tabelle in der DB angelegt habe. Die Sortierung des Views geht weitaus schneller als die der eigentlichen Tabelle mit ihren Lookup-Feldern. Leider war es mir bislang nicht möglich, die Sortierung des Vies zu beschleunigen, sie benötigt noch immer ca. 26 sec. Und da noch ca. 700.000 Einträge folgen werden, muß ich leider auf die Sortierung dieses speziellen Views beim Programmstart verzichten. Immerhin geht die Sortierung mittels Zuweisungen an IndexFieldNames mehr als 10 mal schneller als mittels Manipulation der Order-Klausel im Select-Befehl, die dauerte nämlich 157 Sekunden.

Perlsau 5. Mai 2013 19:48

Nachtrag 2 zu: Optimierung Datenbankzugriff Firebird
 
Wenn ich die Sortierung ganz weglasse, benötigt der Start noch immer ca. 11 Sekunden. Kommentiere ich auch noch das Lokalisieren der zuletzt angezeigten Datensätze aus (locate), bin ich bei 46 Millisekunden Startzeit. Ich werde mich also darauf beschränken, die Haupttabelle, die noch gar nicht implementiert ist, zu sortieren und lokalisieren. Das werden bei einem Durchschnittsanwender sicher nicht mehr als 10- bis 20tausend Einträge werden ...

mkinzler 5. Mai 2013 20:07

AW: Optimierung Datenbankzugriff Firebird
 
Und wenn du eine Query nimmst und im SQL-Statement sortierst?

Perlsau 5. Mai 2013 20:14

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von mkinzler (Beitrag 1214233)
Und wenn du eine Query nimmst und im SQL-Statement sortierst?

Hab ich im Post #15 bereits dargestellt:

Immerhin geht die Sortierung mittels Zuweisungen an IndexFieldNames mehr als 10 mal schneller als mittels Manipulation der Order-Klausel im Select-Befehl, die dauerte nämlich 157 Sekunden.

Ich hab ja jetzt fast nur noch Queries statt der Table-Komponenten, die bei IBdac im Grunde Datasets sind, wenn ich die Dokumentation richtig verstanden habe. Nur für die paar Tabellen, die sowieso nicht vom Anwender erweitert werden, wie Geschlecht, Anrede usw., hab ich die Tables gelassen. Die Sortiermöglichkeit in der Anwendung bleibt natürlich erhalten, nur überlasse ich es dem Anwwender, ob er die Sortierungen abspeichern will, eventuell sogar mit einer Warnung, daß das die Ladezeit des Programms enorm verzögert. Ich weiß nicht, wie andere das machen, und ich hab auch gerade kein Beispiel zur Hand, bei dem das Sortieren und Lokalisieren die Ladezeit der Anwendung nicht dermaßen vergrößert. Vielleicht ist das ja alles ganz normal :?

Perlsau 5. Mai 2013 20:57

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von IBExpert (Beitrag 1214208)
Wenn du noch mehr Infos zu Firebird brauchst und dir mal hier und da Zeit dafür nehmen kannst, dann würde ich mal so nach und nach die Videos auf http://www.youtube.com/user/IBExpertise oder im IBExpertLive Player (http://ibexpert.net/ibe/index.php?n=Doc.IBExpertLive) anschauen, da sind auch einige deutschsprachige Schulungen von uns dabei.

Da ist nur ein Video auf deutsch, nämlich das mit der Shadow-Datei. Die anderen sind allesamt auf englisch. Lesen und schreiben geht bei mir einigermaßen, aber englisch verstehen, noch dazu wenn schnell gesprochen wird, macht mir Schwierigkeiten.
Naja, ich werd' mich dennoch irgendwie durchwurschteln ... :wiejetzt:

IBExpert 6. Mai 2013 06:39

AW: Optimierung Datenbankzugriff Firebird
 
Moin,

die deutschen Videos sind im IBExpertLive, auf Yourtube ist wirklich nur eins auf deutsch

IBExpert 6. Mai 2013 06:48

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von tsteinmaurer (Beitrag 1214229)
Zitat:

Locate ist meistens ein blödes Verfahren, weil eben alle Records zum Client geliefert werden, bis derjenige kommt, den du haben wolltest
Um Mißverständnissen vorzubeugen. Das war zu Zeiten der BDE. IBObjects zum Beispiel ist da viel cleverer. IBDac eventuell auch. Ist mit der Trace API nun alles schön transparent, was da von den Zugriffskomponenten teilweise verbrochen wird. Aber das Thema Trace API wurde ja bereits erwähnt ... :thumb:

hier mal ein Ausschnit aus der aktuelle Implementation TCustomSQLDataSet.LocateRecord
in XE4 unit Data.SqlExpr, das sieht mir nicht besonders clever aus.

Der rennt sogar zwei mal durch die Datenmenge, wenn beim ersten Durchlauf keine
Übereinstimmmung gefunden wurde. Und diese Implementation ist leider nicht unüblich,
auch wenn andere Komponenten das ggf irgendwie anders lösen, da sollte man sich aber
nicht drauf verlassen.

Code:
    First;
    while not EOF do
    begin
      if CheckValues(AFields, Values, CaseInsensitive, PartialLength) then
        break;
      Next;
    end;
    { if not found, reset cursor to starting position }
    bFound := not EOF;
    if not bFound then
    begin
      First;
      while not EOF do
      begin
        if CheckValues(SaveFields, StartValues, False, False) then
          break;
        Next;
      end;
    end;
    Result := bFound;
"Das war zu Zeiten der BDE" ist da also doch nicht ganz zutreffend ...

Furtbichler 6. Mai 2013 07:05

AW: Optimierung Datenbankzugriff Firebird
 
Ich befürchte, Du wirst nicht darum herum kommen, dich zu entscheiden: Entweder hohe Ladezeiten oder einen etwas anderen Aufbau deines UX: Wieso soll der Anwender durch 300.000 Datensätze scrollen dürfen? Wieso muss er nach der (z.B.) Schuhgröße oder anderen, vollkommen unwichtigen, Eigenschaften sortieren können? Kann man sein Anliegen nicht anders lösen? Wir haben z.B. einmal ein ähnliches Problem dadurch gelöst, in dem der Anwender genau befragt wurde, wieso er denn darauf besteht, 100.000 Datensätze im Grid zu sehen: Dabei hat sich dann herausgestellt, das er diese Daten filtert und exportiert, um sie in EXCEL weiter zu verarbeiten. Und dazu hat er die Daten sortiert und bestimmte Bereiche rausgeschnippelt.

Also haben wir ihm kurzerhand ein Export-Tool geschrieben, was nun viel schneller geht und sind erstens unser Problem los (wie sortiert man eine Tabelle mit 50 Spalten und > 1Mio Zeilen performant in der GUI?) und zweitens sein Problem: Die Anwendung lief nur noch auf den aktuellsten PC mit schneller CPU und viel RAM. Unser Exporttool läuft überall.

Die UX haben wir dahingehend verändert, das er zur Darstellung seiner Daten immer einen Filter setzen muss, d.h. es werden nicht alle Daten angezeigt. Lässt er diesen leer, dann weiß er wenigstens, warum das jetzt so lange dauert.

Ich kenne FB nicht so gut, aber i.a. sind Sortieroperationen auf indexierten Spalten wesentlich schneller als auf Spalten ohne Index. Ist auch irgendwie logisch. Ich glaube auch, das FB den Index nicht verwendet, wenn dieser z.B. aufsteigend sortiert ist, man selbst aber absteigend sortieren möchte.

Du könntest allen Spalten deiner Tabelle nun einen Index spendieren, aber das wäre irgendwie bescheuert, denn nun hast Du bei der Datenänderung ein Performanceproblem, wenn es viele sind. Zudem kann man den Index nicht mehr so gut verwenden, wenn man nach mehreren Spalten sortieren will.

[QUOTE=IBExpert;1214261]
Zitat:

Zitat von tsteinmaurer (Beitrag 1214229)
hier mal ein Ausschnit aus der aktuelle Implementation TCustomSQLDataSet.LocateRecord in XE4 unit Data.SqlExpr, das sieht mir nicht besonders clever aus.

Der rennt sogar zwei mal durch die Datenmenge...

Also wenn ich das richtig sehe, sucht er ab der aktuellen Cursorposition bis zum Ende. Wie soll man das schneller machen (ok, Index berücksichtigen). Wenn nichts gefunden wurde, fängt er von vorne an. Von 'zwei mal durch die Datenmenge' kann man nun wirklich nur dann reden, wenn man sich ganz vorne befindet und der zu suchende Datensatz nicht vorhanden ist.

Allerdings ist hier ein wirklicher Lapsus: Beim zweiten Durchlauf sollte man aus der Schleife heraus, wenn man den ursprünglichen Record ein zweites Mal untersucht. Da man ab hier eh alles schon geprüft hat, kann man gleich ans Ende springen und die Schleife beenden.

Also: Locate funktioniert, wenn es etwas zu finden gibt und ist dann lahm (ok, und nicht wirklich clever), wenn es nichts zu finden gibt.

Sir Rufo 6. Mai 2013 07:34

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von Furtbichler (Beitrag 1214262)
Zitat:

Zitat von IBExpert (Beitrag 1214261)
hier mal ein Ausschnit aus der aktuelle Implementation TCustomSQLDataSet.LocateRecord in XE4 unit Data.SqlExpr, das sieht mir nicht besonders clever aus.

Der rennt sogar zwei mal durch die Datenmenge...

Also wenn ich das richtig sehe, sucht er ab der aktuellen Cursorposition bis zum Ende. Wie soll man das schneller machen (ok, Index berücksichtigen). Wenn nichts gefunden wurde, fängt er von vorne an. Von 'zwei mal durch die Datenmenge' kann man nun wirklich nur dann reden, wenn man sich ganz vorne befindet und der zu suchende Datensatz nicht vorhanden ist.

Öhm, du hast schon gesehen, dass das mit
Delphi-Quellcode:
First
startet (Position an den Anfang des DataSets setzen).
Da ist also nix von ab hier.

Und der zweite Suchlauf sucht einfach nur nach dem Datensatz, der aktiv war, bevor die Suche begann. Wenn dieser der letzte Datensatz im DataSet ist, dann wird die Datenmenge im WorstCase zweimal komplett durchsucht.

IBExpert 6. Mai 2013 07:45

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von Furtbichler (Beitrag 1214262)
Ich kenne FB nicht so gut, aber i.a. sind Sortieroperationen auf indexierten Spalten wesentlich schneller als auf Spalten ohne Index. Ist auch irgendwie logisch. Ich glaube auch, das FB den Index nicht verwendet, wenn dieser z.B. aufsteigend sortiert ist, man selbst aber absteigend sortieren möchte.

Wenn ein absteigender index existiert wird der auch benutzt, jedenfalls dann, wenn aus der eigenen Anwendung ein passendes SQL kommt und ide nicht versucht, das im Speicher zu sortieren. Der Index muss aber passend asc oder desc sein. Das kannst du beim Anlegen des Index selbst bestimmen und auf jeder Tabelle können pro Feld zum Beispiel ein aufsteigender und ein absteigender index erstellt werden.

Dann aber nicht beschweren, das das Schreiben extrem lahm wird. Bei 16k Pagesize gehen bis zu 818 single column indices pro Tabelle. Dann werden bei jedem Insert oder Update nicht nur die zugehörige Datenpage neu geschrieben, sondern auch noch mal bis zu 818 Indexpages.

Denk noch mal über die Anregungen von Furtbichler nach. Es ist ganz selten sinnvoll, in einem Grid hundertausende Records ungefiltert anzuzeigen. Aber bitte dann nicht mit den Filtereigenschaften arbeiten, die sind häufig genau so blöde implementiert wie locate.

Ohne kleine Datenmenge fliegt dir auch ab einer gewissen Datensatzanzahl die Funktionalität mit win32 schnell um die Ohren, dann startet dein Programm ab einer gewissen Datensatzanzahl gar nicht mehr, weil das Grid inkl Overhead bei so vielen Records auch schnell mal die 2GB Grenze sprengt.


Zitat:

Zitat von Furtbichler (Beitrag 1214262)
Wenn nichts gefunden wurde, fängt er von vorne an. Von 'zwei mal durch die Datenmenge' kann man nun wirklich nur dann reden, wenn man sich ganz vorne befindet und der zu suchende Datensatz nicht vorhanden ist.

Ganz vorne befindet man sch immer, weil ganz oben ein First steht ;-)

Aber wie du schon sagst, 2 komplette Durchläufe gibt es nur wenn es keine Übereinstimmung gibt und vorher der letzte aktiv war.
Dafür muss ich aber nicht alle Daten zum Client schicken, dafür gibt es eigenständige SQL Befehle.

Bei kleinen Datenmenge ist die Implementation in den Komponenten fast egal, aber 300000 Records sind schon mal per se keine kleine Datenmenge

jobo 6. Mai 2013 08:01

AW: Optimierung Datenbankzugriff Firebird
 
Ich kann Furtbichlers Maßnahmen nur unterstreichen.
Wir bauen Systeme, die so arbeiten:
Verwendung z.B. ADO mit MAXRECORDS z.B. gleich 1000
Ableitung von TADOQuery/TADODataset wandelt Filter & Sort in Where-Bedingung/Order By um.
Mehrere Millionen Datensätze
Im Backend wird generell eine Dimension rausgefiltert, bleiben z.B. 200000 DS in großen Datenmengen
Öffnen/Sortieren von komplexen Datenmengen dauert leider noch mehrere Sekunden
Das ist natürlich nicht gewünscht, dafür gibt es spezialisierte Suchmasken mit einer handvoll Suchfeldern (indiziert)
Öffnen der großen Datenmengen über PK Filter aus Suchmaske.
Suchmasken und Ergebnisdarstellung liegen deutlich unter 0,5 Sekunden

Der Kunde kann unabhängig davon auch die großen Datenmengen auf jedem Feld filtern oder sortieren. Wenn er schlau ist, filtert er erst nährungsweise im Sekundenbereich auf eine kleine, relevante(!) Menge, dann sortiert er im Millisekundenbereich.

Auch ein Locate auf vorgefilteterten, kleinen Datenmengen läuft hinreichend schnell.

Perlsau 6. Mai 2013 09:51

Gesammelte Antworten
 
Zitat:

Zitat von IBExpert (Beitrag 1214259)
Moin, die deutschen Videos sind im IBExpertLive, auf Yourtube ist wirklich nur eins auf deutsch

Ja, das schau ich mir auf jeden Fall nochmal an. Wenn ich mich richtig an das letzte Mal erinnere, werden viele Funktionen erklärt, die in der Personalversion gesperrt sind. Aber egal, ich warte jetzt auf das neue Passwort, mein altes scheint nicht mehr gültig zu sein.

Zitat:

Zitat von Furtbichler (Beitrag 1214262)
Ich befürchte, Du wirst nicht darum herum kommen, dich zu entscheiden: Entweder hohe Ladezeiten oder einen etwas anderen Aufbau deines UX: Wieso soll der Anwender durch 300.000 Datensätze scrollen dürfen? Wieso muss er nach der (z.B.) Schuhgröße oder anderen, vollkommen unwichtigen, Eigenschaften sortieren können? Kann man sein Anliegen nicht anders lösen?

Ja, eine ähnliche Einsicht habe ich auch bereits gewonnen. Bei der riesigen Tabelle geht es um Daten aus der OpenGeoDB bzw. aus OpenStreetMaps: Weltweite Orte, Postalcodes, Länder, Längen- und Breitengrade usw. Ich habe gestern weiter herumprobiert und lasse jetzt via ComboBox-Auswahl nur noch Daten eines ausgewählten Landes anzeigen, wahlweise natürlich auch alle. Eine zweite ComboBox filtert nach Bundesländern vielleicht eine dritte noch nach Städten. Diese Filterung betrifft das View, die eigentliche Tabelle wird ja gar nicht angezeigt, sondern steht bei der Adresseingabe zur Verfügung, um dieselbe zu erleichtern. Findet der Anwender seine speziellen Adressbestandteile bei der Adresseingabe nicht, kann er die Daten in einem gesonderten Formular ergänzen.

Zitat:

Zitat von Furtbichler (Beitrag 1214262)
Wir haben z.B. einmal ein ähnliches Problem dadurch gelöst, in dem der Anwender genau befragt wurde, wieso er denn darauf besteht, 100.000 Datensätze im Grid zu sehen: Dabei hat sich dann herausgestellt, das er diese Daten filtert und exportiert, um sie in EXCEL weiter zu verarbeiten. Und dazu hat er die Daten sortiert und bestimmte Bereiche rausgeschnippelt. Also haben wir ihm kurzerhand ein Export-Tool geschrieben, was nun viel schneller geht und sind erstens unser Problem los (wie sortiert man eine Tabelle mit 50 Spalten und > 1Mio Zeilen performant in der GUI?) und zweitens sein Problem: Die Anwendung lief nur noch auf den aktuellsten PC mit schneller CPU und viel RAM. Unser Exporttool läuft überall. Die UX haben wir dahingehend verändert, das er zur Darstellung seiner Daten immer einen Filter setzen muss, d.h. es werden nicht alle Daten angezeigt. Lässt er diesen leer, dann weiß er wenigstens, warum das jetzt so lange dauert.

Das sehe ich inzwischen auch so: Es gibt eigentlich keinen Grund, eine Million Datensätze zum Scrollen bereitzustellen. Und Export der Geo-Daten ist auch nicht notwendig. Die einfach dazu verwendet, Adress-Eingaben zu verifizieren. So möchte ich z.B. die Möglichkeit bereitstellen, via integriertem Webbroser von Google-Maps anzeigen zu lassen, wo sich die eingegebene Location befindet.

Zitat:

Zitat von Furtbichler (Beitrag 1214262)
Ich kenne FB nicht so gut, aber i.a. sind Sortieroperationen auf indexierten Spalten wesentlich schneller als auf Spalten ohne Index. Ist auch irgendwie logisch. Ich glaube auch, das FB den Index nicht verwendet, wenn dieser z.B. aufsteigend sortiert ist, man selbst aber absteigend sortieren möchte.

Vor allem gibt es bei Views keinen Index! Das hab ich gestern herausgefunden. Es besteht keine Möglichkeit, Views zu indexieren, da es sich ja um virtuelle Tabellen handelt, die nicht physikalisch in der Datenbank existieren. Views stellen ja im Grunde ein Select-Resultat dar. Views verwende ich deshalb, weil z.B. die Tabelle Orte etliche Verknüpfungen zu Untertabellen aufweist wie z.B. zur Tabelle Land, und ich so auf Lookup-Felder in den entsprechenden Queries verzichten kann. Die Sortierung von Lookup-Feldern dauert seltsamerweise länger als die Sortierung des Views.

Zitat:

Zitat von Furtbichler (Beitrag 1214262)
Du könntest allen Spalten deiner Tabelle nun einen Index spendieren, aber das wäre irgendwie bescheuert, denn nun hast Du bei der Datenänderung ein Performanceproblem, wenn es viele sind. Zudem kann man den Index nicht mehr so gut verwenden, wenn man nach mehreren Spalten sortieren will.

Wie gesagt, Views kann man nicht indexieren. Ich geh jetzt nach dem Frühstück gleich mal dran und reduziere die Datenmenge so vernünftig, wie ich es vermag.

Achso, Frage: Was ist ein UX? User-Schnittstelle?

jobo 6. Mai 2013 11:39

AW: Gesammelte Antworten
 
Zitat:

Zitat von Perlsau (Beitrag 1214291)
Wie gesagt, Views kann man nicht indexieren. Ich geh jetzt nach dem Frühstück gleich mal dran und reduziere die Datenmenge so vernünftig, wie ich es vermag.

Das spielt keine Rolle, die Datenbankphysik- Existenz und Art des Index bspw.- hat nichts mit dem Modell zu tun. Die Wirksamkeit eines Index sollte unabhängig vom Zugriff gegeben sein. Ich kenne es nicht anders.
Wirkt ein Index nicht, dann weil der Optimizer es nicht schnallt - oder der Entwickler-. Ein View ist nichts anderes als ein vorbereitetes Selectstatement.
Du kannst es ja ausprobieren und die Zugriffszeiten testen. Die sollten gleich sein.
(Ein View hat natürlich auch noch andere Zwecke, Interfaceschicht, Abstraktionsschicht, Berechtigungsschicht, ..), aber darum geht es hier ja gerade nicht.

Perlsau 6. Mai 2013 12:00

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von jobo (Beitrag 1214277)
Ich kann Furtbichlers Maßnahmen nur unterstreichen.

Ich auch!

Zitat:

Zitat von jobo (Beitrag 1214277)
Verwendung z.B. ADO mit MAXRECORDS z.B. gleich 1000

Das gibt's beim IBDac-Query nicht.

Zitat:

Zitat von jobo (Beitrag 1214277)
Ableitung von TADOQuery/TADODataset wandelt Filter & Sort in Where-Bedingung/Order By um.

Das versuche ich gerade, erhalte aber eine Fehlermeldung beim Versuch, den Filter zu setzen. Natürlich hab ich das bereits viele Male gemacht, aber noch nie mit den IBDac-Queries. Die Fehlermeldung lautet: Feld nicht gefunden. Dabei wird als Name des angeblich nicht gefundenen Feldes das Filterkriterium gemeldet:

Column unknown
BRASILIEN


Die Procedure, die aufgerufen wird:
Delphi-Quellcode:
procedure TDatMod.SetFilter_OrteLand(Land: String);
begin
  View_Orte.FilterSQL := 'V_LAND=' + Land;
end;

// Example aus IbDac.pdf:
// Query1.FilterSQL := 'Dept >= 20 and DName LIKE ''M%''';
Wobei das Property FilterSQL laut Dokumentation nichts anderes macht als:
Used to change the WHERE clause of SELECT statement and reopen a query.

Übrigens derselbe Fehler, der auch beim Setzen der gewöhnlichen Filtereigenschaft auftritt, wie ich es zuerst versucht hatte:
Delphi-Quellcode:
procedure TDatMod.SetFilter_OrteLand(Land: String);
begin
  View_Orte.Filtered := False;
  View_Orte.Filter := 'V_LAND=' + Land;
  View_Orte.Filtered := True;
end;
Schon irgendwie seltsam ... vielleicht 'n Bug ...

mkinzler 6. Mai 2013 12:11

AW: Optimierung Datenbankzugriff Firebird
 
Delphi-Quellcode:
View_Orte.FilterSQL := 'V_LAND=' + QuotedStr(Land);

Lemmy 6. Mai 2013 12:12

AW: Optimierung Datenbankzugriff Firebird
 
nein, das ist korrekt:

Zitat:

Zitat von Perlsau (Beitrag 1214299)
Delphi-Quellcode:
procedure TDatMod.SetFilter_OrteLand(Land: String);
begin
  View_Orte.FilterSQL := 'V_LAND=' + [B]QuotedStr(Land)[/B];
end;

du musst den Suchert in ' einschließen - ist ja auch ein String den Du suchst...

Grüße

Perlsau 6. Mai 2013 12:17

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat von Lemmy (Beitrag 1214301)
du musst den Suchert in ' einschließen - ist ja auch ein String den Du suchst...

Hi Lemmy,
manchmal sieht man den Baum vor lauter Wald nicht mehr. Das funktioniert natürlich :thumb:

Hansa 6. Mai 2013 13:49

AW: Optimierung Datenbankzugriff Firebird
 
Zitat:

Zitat:

Zitat von jobo (Beitrag 1214277)
Verwendung z.B. ADO mit MAXRECORDS z.B. gleich 1000

Das gibt's beim IBDac-Query nicht.
Das gibts wirklich nicht, aber es gibt z.B. :
Code:
SELECT FIRST 1000 FROM ...
Aber mich wundert etwas, dass TClientDataSet noch nicht vorgeschlagen wurde. Es geht doch darum, dass schon sehr viele Daten angezeigt und/oder sortiert werden sollen ? Was spricht da gegen ein ClientDataSet (CDS) ? Ohne jetzt eine Indexorgie auf Datenbankebene anzetteln zu müssen könnte man die Daten doch zunächst mal in ein CDS einlesen und dieses könnte man ja anzeigen (geht sogar mit DBgrid) oder es lässt sich einfach sortieren. Für Letzteres reicht ja schon lediglich die Angabe des zu sortierenden Feldes. Also z.B. so:
Code:
CdsDM.CDS.IndexFieldNames := 'NR';
Was spricht dagegen, das so zu machen ?

Perlsau 6. Mai 2013 14:02

AW: Optimierung Datenbankzugriff Firebird
 
[QUOTE=Hansa;1214317]
Zitat:

Ohne jetzt eine Indexorgie auf Datenbankebene anzetteln zu müssen könnte man die Daten doch zunächst mal in ein CDS einlesen und dieses könnte man ja anzeigen (geht sogar mit DBgrid) oder es lässt sich einfach sortieren.
Ich hab's jetzt so gelöst: Oberhalb des Grids liegt nun ein Panel, das verschiedene Auswahl-Komponenten aufnimmt:

Eine TComboBox, die die sortierten Ländernamen enthält und an Position 0 den Eintrag _Alle. Stellt der Anwender die ComboBox auf _Alle, entzieht ihm die Anwendung die Möglichkeit, beim Start sortieren zu lassen.
Dafür liegt auf dem Panel noch eine TDBCheckBox, die mit bei Auswahl von 0 unchecked wird und gleichzeitig readonly. In der Doku bzw. Hilfe wird das dem Anwender dann genauer erklärt werden.
Ich bin jetzt gerade dabei, weitere Auswahl-Combos zur Einschränkung der Datenmenge zu implementieren.
Diese Lösung gefällt mir recht gut, weil sie mir sehr flexibel scheint und die Sortierzeit auf ein bis zwei Sekunden beschränkt, wobei ich bei weiteren Einschränkungen sicher noch unter eine Sekunde komme.

Ich glaube nicht, daß die Sortierzeit bei Verwendung eines CDS wesentlich kürzer wäre, denn die Arbeit, die der Prozessor dabei zu verrichten hat, ist im Grunde dieselbe.

IBExpert 6. Mai 2013 14:46

AW: Gesammelte Antworten
 
Zitat:

Zitat von Perlsau (Beitrag 1214291)
Ja, das schau ich mir auf jeden Fall nochmal an. Wenn ich mich richtig an das letzte Mal erinnere, werden viele Funktionen erklärt, die in der Personalversion gesperrt sind. Aber egal, ich warte jetzt auf das neue Passwort, mein altes scheint nicht mehr gültig zu sein.

Sende mir doch mal deine da eingetragene email an support at ibexpert punkt com, ich seh da kein Kennwortversand in der pipeline

Perlsau 6. Mai 2013 14:56

AW: Gesammelte Antworten
 
Zitat:

Zitat von IBExpert (Beitrag 1214342)
[Sende mir doch mal deine da eingetragene email an support at ibexpert punkt com, ich seh da kein Kennwortversand in der pipeline

Das siehst du nicht, weil das Kennwort bereits um 10:17 Uhr bei mir eingetroffen ist – und es funktioniert.

IBExpert 6. Mai 2013 15:36

AW: Optimierung Datenbankzugriff Firebird
 
aha, so soll das ja auch sein :-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:00 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