Entwickler-Ecke
Datenbanken - Firebird abfragen sehr langsam
BrixxtoN - Mo 05.12.11 15:11
Titel: Firebird abfragen sehr langsam
Hallo,
wenn ich eine abfrage "select * from kunden" mache, dauert es sehr lange ca. 1min bis das ergebniss angezeigt wird.
Weis jemand wie ich das beschleinigen kann.
Kundenanzahl: 26390
Datenbank: Firebird
Server: Firebird 2.5
Windows 7
Core i7
4 GB RAM
Delphi 2010
Komponenten: tSQLConnection, tSimpleDataSet (tSQLQuery genau so langsam), tDataSource, tDBGrid
Nersgatt - Mo 05.12.11 15:16
26.000 ist ja nun auch nicht gerade wenig. Und so viele Kunden in einer Liste - da findet kein User das, was er sucht. Filtere die Datensätze raus, die der User wirklich benötigt.
Du solltest aber SELECT * immer vermeiden. Beschränke das auf die Felder, die Du wirklich brauchst.
Große Blob-Felder in der Tabelle? Bei Blobs mit vielen Daten ist es evtl. sinnvoll, sie in eine 1:1-Tabelle auszulagern.
Datenbank liegt lokal? Oder Netzwerk? Wie sieht der Server aus? Hatte mal einen Kunden, der sich über eine langsame Software beschwerte. Auf die Frage, wie viel Ram hat der Server denn sagte er "1 GB" (bei einem Windows 2003-Server). Auf 4 GB aufgerüstet - zack, Datenbank 3x schneller.
BrixxtoN - Mo 05.12.11 15:28
Ich finde das 26000 Datensätze nicht viel sind.
Wenn ich die selbe abfrage mit dBase-Datenbank und ADS-Komponenten mache geht das in 2-3 Sekunden.
Komponenten: ADSConnection, ADSQuery, DataSource, DBGrid
Datenbank ist Momentan auf meinem Notebook (Lokal) mit Windows 7, Core i7 und 4 GB RAM.
zuma - Mo 05.12.11 16:38
26000 dürfte auch gar kein Problem sein (selbst mit Select * unter 2 sec).
Ich lese in manchen Modulen zw. 200.000 und 300.000 DS aus der DB, schaufel die in ein ClientDataSet und das ganze in unter 10 sec. inkl. Anzeige in Maske.
Haste Indexe auf der Tabelle ?
Das spielt definitiv ne große Rolle bei der Geschwindigkeit.
Indiziertes Lesen ist gegenüber sequentiellem Lesen um ein vielfaches schneller.
Wenn es langsam ist, liegt es eben auch oft am Netzwerk (falls das ne Rolle bei dir spielt) oder ne Firewall/Antivirus kann auch mal für einiges an Zeitverlust sorgen.
mkinzler - Mo 05.12.11 16:39
Wie lautet die Endung der Datenbank?
BrixxtoN - Mo 05.12.11 17:14
Datenbankendung ist FDB.
Ja ich habe 3 Indexe.
1. Index = Spalte ID als Unique Index
2. Index = Spalte Kundennr
3. Index = Spalten STANDORT, GELOESCHT, NOEXPORT
Ich hoffe die Indexe sind richtig aufgebaut.
1. Test
ADS-Komponenten und dBase Datenbank = 2-3 Sekunden
2. Test
ADO-Komponente und ODBC für Firebird = 2-3 Sekunden
3. Test
dbExpress und Firebird = 1 Minute
mkinzler - Mo 05.12.11 17:16
Wie sieht die Abfrage aus?
BrixxtoN - Mo 05.12.11 17:25
Bei den Tests habe ich
verwendet.
In meiner Software ist die abfrage
SQL-Anweisung
1:
| select * from kunden where (geloescht!=1 or geloescht is null) |
mkinzler - Mo 05.12.11 17:30
Dann hilft ja keiner der Indizes. Das Problem scheint aber eher an dbExpress zu liegen, sonst wäre die Abfrage per ODBC ja auch nicht schneller
BrixxtoN - Mo 05.12.11 17:40
Wie müsste ich die Indezes aufbauen das es besser wird?
Das hab ich mir auch gedacht das es an dbExpress liegen müsste.
Es gibt doch auch andere Entwickler die dbExpress nutzen mit mehr als 26000 Datensätzen, es wundert mich das bei anderen funktioniert.
Ich habe es auch auf verschidenen Rechnern getestet, weil ich dachte es liegt an der Entwicklungsumgebung auf meinem Notebook.
Es ist auf allen Rechnern das gleiche Problem.
baka0815 - Mo 05.12.11 17:42
Die Indizes helfen ja nur, wenn du diese auch in der Abfrage brauchst.
Wenn du oft where geloescht = :Wert benutzt, dann macht ein Index auf die Spalte "geloescht" Sinn.
Wenn du jedoch einfach select * from kunden ohne WHERE-Bedingung ausführst, sind die Indizes egal.
BrixxtoN - Mo 05.12.11 17:48
Dann ist der 3. Index für meine Abfrage schon richtig.
3. Index = Spalten STANDORT, GELOESCHT, NOEXPORT
SQL-Anweisung
1:
| select * from kunden where (geloescht!=1 or geloescht is null) |
mkinzler - Mo 05.12.11 18:07
Nein, weil du GELOESCHT in der Where-Clause abfegragt wird.
BrixxtoN - Mo 05.12.11 19:00
3. Index = Spalten STANDORT, GELOESCHT, NOEXPORT
SQL-Anweisung
1:
| select * from kunden where (geloescht!=:wert or geloescht=:wert2) |
Params:
wert=1
wert2=Null
Ist das jetzt richtig, macht jetzt 3. Index sinn.
jasocul - Di 06.12.11 00:06
Dein 3. Index ist eine Kombination. Wenn du nur eines dieser Kombi-Felder in der Where-Klausel hast, nützt das nichts. Außerdem fragst auf ungleich ab. Das kann auch dazu führen, dass ein Index nicht gezogen wird.
baka0815 - Di 06.12.11 10:20
Du solltest auch nicht geloescht=:wert nutzen wenn wert=null. Nimm statt dessen lieber geloescht is null.
Performanter wäre es jedoch die Spalte geloescht auf not null mit einem Default-Wert (0) zu versehen.
Dann kannst du dir die Abfrage auf null sparen und die DB kann den Index performanter gestalten, da der null-Fall nicht extra behandelt werden muss.
BrixxtoN - Di 06.12.11 12:22
Neuer Test:
4. Index = Spalte GELOESCHT
SQL-Anweisung
1:
| select * from kunden where geloescht=:wert |
Params:
wert=0
Genau so langsam.
BrixxtoN - Di 06.12.11 12:52
Ich habe festgestellt, wenn ich das Notizfeld (BLOB SUB_TYPE TEXT) aus der Datenbank lösche, hab ich die Probleme nicht mehr.
Nersgatt - Di 06.12.11 12:54
Tja, wie ich bereits in meiner ersten Antwort sagte: Blobfelder machen gern Probleme. Lager sie in eine 1:1-Tabelle aus.
BrixxtoN - Di 06.12.11 13:02
Ich brauche das Feld zur anzeige und wenn ich es auslager muss ich trotzdem noch einer SQL-Abfrage auf das Feld machen.
Ist das dan schneller?
Was ich noch immer nicht verstehe, warum funktioniert das mit ADO und ADS.
mkinzler - Di 06.12.11 13:06
Ab Firebird2.5 verhalten sich kurze Textblobfelder (< 32KB) wie Varchar-Felder.
dbExpress funktioniert halt anders.
Nersgatt - Di 06.12.11 13:49
Große Blobfelder werden in Firebird nicht in der DataPage des Datensatzes gespeichert, sondern in eigenen Blob Pages irgendwo anders in der Datenbank. Somit muss der Server diese Daten von ganz anderen Stellen abrufen, als den Rest der Daten. In der Row steht praktisch nur ein Verweis auf das Blob. Wenn die Zeile in der Datenbank klein ist, kann der Server sogar mehrere Datensätze in einer Page speichern und so auch schneller abrufen.
Dazu kommt, dass immer komplette Blob-Pages gespeichert werden. Wenn Deine Pagesize z.B. 4K ist, und Du ein 5K-Blob speicherst, werden dafür 2 komplette Blob-Pages verwendet, die der Server beim Abrufen auch wieder lesen muss.
Daher, ruf die Daten aus dem Blobfeld erst dann ab, wenn Du es wirklich brauchst (also zur Anzeige). Kannst Dir ja eine Query machen, die Du schon vorbereitest (prepared Query). Das wird die Last auf dem Server stark reduzieren. Und auch der Netzwerkverkehr ist natürlich deutlich geringer.
baka0815 - Di 06.12.11 14:10
Das liegt vermutlich daran, wie diese die BLOB-Felder cachen.
Wir verwenden (leider) noch die BDE und überlegen auf SQLDirect umzusteigen. Wenn wir ein select * from <Tabelle> auf eine Tabelle mit LOB-Felder machen, dauert das Query.Next bei der BDE um einiges länger als bei SQLDirect (Faktor 100+).
BrixxtoN - Mi 07.12.11 11:56
Danke an alle für die Mühe.
Ich werde versuchen das umzusetzen was der Jens vorgeschlagen hat.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!