Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Index setzen? (https://www.delphipraxis.net/190964-index-setzen.html)

Gruber_Hans_12345 24. Nov 2016 09:14

Datenbank: Firebird • Version: 2.5 • Zugriff über: IBConsole

Index setzen?
 
Ich habe folgendes SQL
Code:
SELECT MAX(DATUM), USERID FROM BUCHUNGEN GROUP BY USERID
das benötigt ca. 4sekunden bei 800000 Datensätze.

Habe nun schon alle Indexe gesetzt ASC und DESC für beide Felder - es ändert sich allerdings nichts an der Ausführungsgeschwindigkeit.

Gibt es da keinerlei Möglichkeiten?

TRomano 24. Nov 2016 10:36

AW: Index setzen?
 
Hast Du im Ausführungsplan geschaut, ob er die Indices auch benutzt ?

Gruber_Hans_12345 24. Nov 2016 10:50

AW: Index setzen?
 
Code:
PLAN (BUCHUNGEN ORDER BUCHUNGEN_USERID)
wobei BUCHUNGEN_USERID der Index ist.
mehr steht da nicht

TRomano 24. Nov 2016 10:54

AW: Index setzen?
 
Dann nutzt er zu mindestens für das ORDER BY einen Index. Gibt es auch für das Feld "DATUM" einen Index ?

Gruber_Hans_12345 24. Nov 2016 11:08

AW: Index setzen?
 
ja da gibt es auch einen Index (bzw zwei - einen ASC und einen DESC)

das sieht man wenn ich folgendes ausführe
Code:
SELECT MAX(DATUM) FROM BUCHUNGEN
das geht in 1ms und verwendet folgenden Plan

Zitat:

PLAN (BUCHUNGEN ORDER BUCHUNGEN_DATUM)
nur eben sobald ich das kombiniere und gruppiere dann siehts nicht mehr so toll aus

bra 24. Nov 2016 11:13

AW: Index setzen?
 
Wir hatten das Problem auch mal. Ich glaube bei max() verwendet Firebird immer einen full table scan. Versuche mal eine where bzw. having-Klausel mit einzubauen (having userid > -1), damit ließ sich das glaube beheben.
Dasselbe tritt auch bei count(*) auf.

Jumpy 24. Nov 2016 11:20

AW: Index setzen?
 
Was wäre mit einem gemeinsamen Index über die zwei Felder?

Gruber_Hans_12345 24. Nov 2016 11:31

AW: Index setzen?
 
Also der Index über beide Felder bringt leider auch nichts (hatte ich auch schon vorher drinnen sowohl ASC als auch DESC)
das having bringt leider auch nichts, nur ein where würde was bringen, wenn ich dadurch die Datenmenge verringere, aber wenn ich alle user brauche, dann hilft es nichts mehr

bra 24. Nov 2016 11:58

AW: Index setzen?
 
Zitat:

Zitat von Gruber_Hans_12345 (Beitrag 1354587)
das having bringt leider auch nichts, nur ein where würde was bringen, wenn ich dadurch die Datenmenge verringere, aber wenn ich alle user brauche, dann hilft es nichts mehr

Es geht nicht darum die Datenmenge zu verringern, sondern mit der where-Klausel den Index zu erzwingen. Das ist ein Problem von Firebird. Es gibt sicher eine Abfrage, die immer alles zurückliefert (z.B. userid > -1, wenn die nicht negativ sein können).
Siehe auch hier: http://www.firebirdfaq.org/faq205/ oder hier: https://sourceforge.net/p/firebird/m...ssage/1300057/
oder hier: http://www.delphipraxis.net/180221-f...index-max.html

Gruber_Hans_12345 24. Nov 2016 12:15

AW: Index setzen?
 
ja ich meinte ja, wenn ich im where ein userid < 20 mache, dann gehts schnell, weil auch weniger Datensätze kommen
wenn ich ein USERID > 0 mach oder > 10 (dann dauerts halt statt 4 sekunden 3.9 sekunden oder so)

und für das Datum habe ich ja einen DESC index, deswegen geht das reine SELECT MAX(DATUM) ohne gruppieren ja auch sehr sehr schnell... nur eben nicht mehr sobald ich nach dem feld gruppiere ...

Ghostwalker 24. Nov 2016 17:13

AW: Index setzen?
 
Vielleicht wärs hilfreich, wenn du etwas mehr über den Kontext sagst.

Aus der Abfrage heraus schließe ich mal, das du für jeden User (userid) das Datum der letzen
Buchung haben willst oder ?

Das würde u.U. ein DISTINCT oder DISTINCTROW helfen (Bin nicht wirklich firm mit Firebird).

Gruber_Hans_12345 25. Nov 2016 07:48

AW: Index setzen?
 
Zitat:

Zitat von Ghostwalker (Beitrag 1354637)
Vielleicht wärs hilfreich, wenn du etwas mehr über den Kontext sagst.

Aus der Abfrage heraus schließe ich mal, das du für jeden User (userid) das Datum der letzen
Buchung haben willst oder ?

Das würde u.U. ein DISTINCT oder DISTINCTROW helfen (Bin nicht wirklich firm mit Firebird).

Ja korrekt ich habe eine Tabelle mit 800.000 Buchungen und will nun zu jedem User (sind 800) die letzte Buchung erfahren.

DISTINCTROW kannte ich gar nicht und weiss auch nicht wie ich das unter firebird verwende ... den eine SELECT DISTINCTROW mag er nicht, da sagt er er kenne das Feld DISTINCTROW nicht.

und beim DISTINCT Weiss ich nicht wie mir der helfen sollte
da bekomme ich gerade mal alle USer raus die irgendwann mal gebucht haben (Aber ja nicht die letze)

tsteinmaurer 25. Nov 2016 08:36

AW: Index setzen?
 
Firebird kann keinen DESCENDING Index für ein GROUP BY verwenden:
http://tracker.firebirdsql.org/browse/CORE-4529

In einem lokalen Test hier mit 800.000 Datensätzen und unterschiedlichen Index-Kombinationen war der Full-Table Scan für deine Abfrage immer schneller, d.h. solange ein Index nicht für die Einschränkung der Ergebnismenge verwendet werden kann (fehlende WHERE Klausel), bremst er dich potentiell sogar aus, da das ein zusätzlicher "Hop" darstellt, bis er zum Datensatz (über den Indexeintrag) kommt.

D.h. ich würde eher in Richtung Firebird-Tuning/Konfiguration gehen und ihm mehr RAM geben. Z.B.:
  • Größer PageCache
  • Bzw. auch (wird sehr gerne auch vergessen!) dem Bereich für temporäre Sachen mehr RAM spendieren. Siehe TempCacheLimit in firebird.conf

Welche Firebird-Architektur verwendest du bzw. wie oft wird dieses Statement eigentlich ausgeführt?

LG

Gruber_Hans_12345 25. Nov 2016 09:10

AW: Index setzen?
 
Zitat:

Zitat von tsteinmaurer (Beitrag 1354665)
Firebird kann keinen DESCENDING Index für ein GROUP BY verwenden:
http://tracker.firebirdsql.org/browse/CORE-4529

In einem lokalen Test hier mit 800.000 Datensätzen und unterschiedlichen Index-Kombinationen war der Full-Table Scan für deine Abfrage immer schneller, d.h. solange ein Index nicht für die Einschränkung der Ergebnismenge verwendet werden kann (fehlende WHERE Klausel), bremst er dich potentiell sogar aus, da das ein zusätzlicher "Hop" darstellt, bis er zum Datensatz (über den Indexeintrag) kommt.

D.h. ich würde eher in Richtung Firebird-Tuning/Konfiguration gehen und ihm mehr RAM geben. Z.B.:
  • Größer PageCache
  • Bzw. auch (wird sehr gerne auch vergessen!) dem Bereich für temporäre Sachen mehr RAM spendieren. Siehe TempCacheLimit in firebird.conf

Welche Firebird-Architektur verwendest du bzw. wie oft wird dieses Statement eigentlich ausgeführt?

LG

Ah okey danke :D

Das Problem ist, es wird teils relativ oft ausgeführt also jede Minute sowas ...
Ich werde es in diesem Fall dann zu dem jeweiligen User die letzte ID speichern, dann gehts natürlich extrem schnell.

Im Moment verwenden wir noch den 2.5 Firebird einmal als Classic und als SuperServer, aber es tut sich natürlich nicht so viel.

tsteinmaurer 25. Nov 2016 09:45

AW: Index setzen?
 
Ja, würde mir z.b. einen Trigger (AFTER INSERT/UPDATE) auf deine Buchungstabelle geben, der dann den "LastTimestamp" in einem zusätzlichen Feld in deiner User-Tabelle wartet.

p80286 25. Nov 2016 14:15

AW: Index setzen?
 
Zitat:

Zitat von Gruber_Hans_12345 (Beitrag 1354669)
Das Problem ist, es wird teils relativ oft ausgeführt also jede Minute sowas ...
Ich werde es in diesem Fall dann zu dem jeweiligen User die letzte ID speichern, dann gehts natürlich extrem schnell.

Nichts für ungut, aber daß jede Minute sich jemand für die letzte Buchung von 800 Benutzern interessiert, halte ich für Blödsinn. Daß irgendjemand sich für die letzte Buchung eines Benutzers oder einer Benutzergruppe interessiert, das glaube ich schon schon eher.

Gruß
K-H

jobo 25. Nov 2016 15:31

AW: Index setzen?
 
sehe ich auch so, es sei denn, wir reden von einer Börsensoftware oder sowas.

Aber
Es ist ja schon ein gangbarer Weg genannt worden, nämlich die denormalisierte Speicherung, die an solch einer Stelle (Konto/Buchaltung mit akt. Saldo, letzter Buchung, ..) nicht ungewöhnlich ist.

und was die Nutzergruppe angeht und nicht so brisante Fälle:
Eine "Gruppe" könnte bspw. die User mit Buchungen innerhalb der letzten 2 Wochen sein- nur mal so als Beispiel. Für meinetwegen Aussagefähigkeit am Telefon (Hotline) oder irgendwelche Statistiken, ergäbe sich aus solche einer -dann flotten- Abfrage Einzelwerte oder Kennwerte mit exakter Genauigkeit für die letzten 2 Wochen oder eben alles was älter ist. Für bspw. Hotline ("in den letzen 2 Wochen liegt keine Buchung vor") oder Management ("die Buchungszahlen in den letzen 14 Tagen steigen kontinuierlich") wäre das m.E. ok.

Ansonsten wäre man dann bei Datawarehouseanwendungen / Datenbanken.

Gruber_Hans_12345 28. Nov 2016 07:39

AW: Index setzen?
 
Zitat:

Zitat von p80286 (Beitrag 1354690)
Zitat:

Zitat von Gruber_Hans_12345 (Beitrag 1354669)
Das Problem ist, es wird teils relativ oft ausgeführt also jede Minute sowas ...
Ich werde es in diesem Fall dann zu dem jeweiligen User die letzte ID speichern, dann gehts natürlich extrem schnell.

Nichts für ungut, aber daß jede Minute sich jemand für die letzte Buchung von 800 Benutzern interessiert, halte ich für Blödsinn. Daß irgendjemand sich für die letzte Buchung eines Benutzers oder einer Benutzergruppe interessiert, das glaube ich schon schon eher.

Gruß
K-H

das stimmt schon direkt nicht aber indirekt, es wird halt zyklisch der status der 800 user geladen, und diese dann gruppiert auf abteilungen dargestellt, wobei man mit incrementalsearch dann sehr schnell zum status des einzelnen users kommen kann.
Da ja auch paar andere infos geladen werden.
Kann man sicher auch besser machen und anders optimieren, aber eben der extremst große und bis jetzt unbekannte zeitfaktor war eben das FireBird beim GroupBy keinen Index verwenden kann.
Und die 800.000 Datensätze in ein paar Jahre dann 8.000.000 werden usw.

Aber es wurde ja schon ein WorkAround genanntm zumindest solange bis FireBird das hoffentlich irgendwann mal optimieren kann :D

jobo 28. Nov 2016 09:57

AW: Index setzen?
 
Zitat:

Zitat von Gruber_Hans_12345 (Beitrag 1354801)
Kann man sicher auch besser machen und anders optimieren, aber eben der extremst große und bis jetzt unbekannte zeitfaktor war eben das FireBird beim GroupBy keinen Index verwenden kann.
Und die 800.000 Datensätze in ein paar Jahre dann 8.000.000 werden usw.

Aber es wurde ja schon ein WorkAround genanntm zumindest solange bis FireBird das hoffentlich irgendwann mal optimieren kann :D

Also was die Optimierbarkeit angeht würde ich mir nicht allzuviel Hoffnungen machen. Das ist ein systematisches Problem was mehr oder weniger zu einem Fullscan führt. Bei Optimierung vielleicht mal eines Tages ein Rangescan oder so.
Wie Du selbst schreibst, skaliert die Lösung nicht und Du weißt schon jetzt, dass Dein Problem mit der "Lösung" Fullscan von Jahr zu Jahr größer wird (oder Tag zu Tag).
Hier muss die Last anders abgefangen werden, um zu einer dauerhaften, skalierenden Lösung zu kommen. Das ist wie bereits geschrieben die denormalisierte Ablage der benötigten Infos oder wenigstens von Hilfswerten.

Bei Denormalisierung wiederum ist dringend zu empfehlen, den Speichervorgang (insert & update) so durch geeignete Datenbankconstraint zu flankieren, dass nieniemals Differenzen in den denormalisiert abgelegten Daten entstehen können(Datenkonsistenz!). Das kann FB mit Sicherheit.

Auf diese Art (Denormalisierung) wird die Last der Abfrage verschoben auf den Zeitpunkt der "Datenentstehung". Sprich die Abfrage wird schneller, der Preis ist langsameres speichern (was aber seltener und gezielter stattfindet).

mkinzler 28. Nov 2016 14:30

AW: Index setzen?
 
Zitat:

Sprich die Abfrage wird schneller, der Preis ist langsameres speichern (was aber seltener und gezielter stattfindet).
Und ist auch weniger aufwendig, da ja genau 1 weiterer Datensatz geändert bzw. erzeugt werden muss.

Gruber_Hans_12345 28. Nov 2016 14:49

AW: Index setzen?
 
ja stimmt schon
nur habe ich auch ähnliche Anwendungsfälle, wo ich dann unterschiedliche Buchungen pro User haben möchten
zB.: generelle die letzte hinzugefügte Buchung
oder die jüngste Buchung (ID und das Datum müssen nicht übereinstimmen - sprich ich kann jetzt eine Buchung mit einem alten Datum erzeugen) - und je nach Situation ist einmal diese Buchung und einmal die andere Buchung als letzte "interessante" Buchung wichtig.
Oder spezielle Buchungen dann doch ausblednen und somit die ID der jüngsten Buchung die als Typ nicht 8 hat ....

Dann benötige ich für jeden dieser spezial Sachen wieder eine eigene Spalte

NicoDE 28. Nov 2016 14:53

AW: Index setzen?
 
Zitat:

Zitat von tsteinmaurer (Beitrag 1354665)
Firebird kann keinen DESCENDING Index für ein GROUP BY verwenden:
http://tracker.firebirdsql.org/browse/CORE-4529

Es fehlt ein "ORDER BY x DESC", um den Index zu verwenden.

jobo 28. Nov 2016 15:43

AW: Index setzen?
 
Zitat:

Zitat von Gruber_Hans_12345 (Beitrag 1354841)
nur habe ich auch ähnliche Anwendungsfälle, wo ich dann unterschiedliche Buchungen pro User haben möchten..
Dann benötige ich für jeden dieser spezial Sachen wieder eine eigene Spalte

Tja, das klingt nun aber auch schon etwas schräg. Buchungen irgendwo dazwischenschieben.. naja, wenn 's sein muss.

Wenn es nunmal eine Anforderung ist:
Hier könnte man vielleicht mit Snapshots / Materialized Views arbeiten, wenn fb das kann. In 3 vielleicht?

Oder den Trigger, der die Aggregatinfo sammelt etwas intelligenter machen. Das meiste dürfte besser sein als dieses Brute Force GROUP BY.

@NicoDE
Ist das wirklich so? Was soll ein Group By mit einem solchen Index anfangen? Ich kann mir nicht vorstellen, dass das hilft.

NicoDE 28. Nov 2016 16:22

AW: Index setzen?
 
Zitat:

Zitat von jobo (Beitrag 1354847)
Was soll ein Group By mit einem solchen Index anfangen?

Man kann die Verwendung des Indizes so 'ermöglichen'. Ansonsten könnte man den Plan/Index explizit angeben und es damit 'erzwingen' (dann muss der Index aber auch existieren und Firebird kann sich nicht mehr anders entscheiden).

Ob das Anlegen und die Verwendung des Indizes Sinn macht oder nicht, ist eine andere Frage (beim Beispiel im Firebird-Tracker nur, wenn man ohnehin sortieren will).

tsteinmaurer 28. Nov 2016 20:14

AW: Index setzen?
 
Zitat:

Man kann die Verwendung des Indizes so 'ermöglichen'
Die Verwendung eines Index ist nicht immer gleichbedeutend mit schneller.

Gruber_Hans_12345 29. Nov 2016 07:46

AW: Index setzen?
 
Zitat:

Zitat von NicoDE (Beitrag 1354842)
Zitat:

Zitat von tsteinmaurer (Beitrag 1354665)
Firebird kann keinen DESCENDING Index für ein GROUP BY verwenden:
http://tracker.firebirdsql.org/browse/CORE-4529

Es fehlt ein "ORDER BY x DESC", um den Index zu verwenden.

Ohhh tatsächlich
mit dem ORDER BY dauert es nun statt 4,0 sekunden 1,2 sekunden !!!!!

Wobei das ganze nun für mich irgendwie noch schräger wird!

Also ohne dem ORDER BY bekomme ich als Plan nun "PLAN (BUCHUNGEN_DATUM ORDER BUCHUNGEN_USERID)" verwendet den Index.
mit ORDER BY USERID DESC : "PLAN SORT ((BUCHUNGEN_DATUM NATURAL))" - da ich ja keinen DESC Index für USERID habe aber das ganze ist trotzdem 3 mal schneller!
mit ORDER BY USERID ASC : "PLAN (BUCHUNGEN_DATUM ORDER BUCHUNGEN_USERID)" hier verwendet er den Index für UserID und ist langsam!

Also sieht es so aus als ob es genau umgekehrt ist, sobald ich ihn zwinge keinen Index zu verwenden dann wirds schneller!

[edit] für den gegentest habe ich den Index auf USERID nun mal gelöscht, nun sind alle gleich schnell bei 1,3 Sekunden sowas....

jobo 29. Nov 2016 07:53

AW: Index setzen?
 
@NicoDE/TE
Es gibt viele Fragen zu dem Thema, wie kann ich eine Indexverwendung erzwingen. Diese Fragen stellen sich zu Recht, wenn der Optimizer aus verschiedensten Gründen zu falschen Annahmen kommt. Dafür gibt es einerseits dann "Tricks", ich sag mal, um den Optimizer zu "übertölpeln" andererseits sogar Implementierungen mit spezielle Notation (meist herstellerspezifisch), denn die Hersteller wissen, dass es manchmal sinnvoll sein kann.

Wenn die Aufgabe aber lautet:
"Zähle alle Daten der Tabelle" (ohne Einschränkung/Where Clause/ Join Einschränkung) kommt der Optimizer zu Recht zu dem Schluss: Wenn ich eh alle Daten zählen muss, kann ich das auch "ganz bequem" von Anfang bis Ende mit einem (1!) Fulltablescan machen.
Der Zwang zum Index würde dazu führen, dass "die arme Engine" je Index Eintrag durch die Tabelle hüpfen muss, um am Ende zu dem überall mal hingesprungen zu sein und zu dem gleichen Ergebnis zu kommen, wie bei einem Fulltablescan ohne Index.

Dabei unberücksichtigt sind natürlich spezielle Indexverfahren oder aber auch die bereits gecachten Tabellenbestandteile. Letztere könnten dem Optimizer bspw. sagen, ich hab eh 90% der Daten im Cache, die 10% lade ich auch noch. Dann ist ein Fulltablescan (plus ggF. Sortierung) lediglich "Kopfrechnen" und sowieso vorzuziehen. Der Ausgang dieser Optimizerentscheidung wird wiederum von der Größe der Tabelle und der Cachegröße und der Häufigkeit der Verwendung der Tabelle abhängen.
Es gibt eine Fülle solcher Kriterien, die es oft schwierig machen, Optimizerentscheidungen nachzuvollziehen- auch sehr unterschiedlich je Produkt und Version.
Hier ist die Sache aber finde ich relativ klar.

Der Ansatz mit Trigger ist relativ naheliegend, auch wenn er noch ausgefeilt werden müsste. Wie mkinzler schon betont hat, der "Impakt" einer solchen Lösung dürfte auch bei relativ hoher Buchungsfrequenz bedeutend geringer ausfallen, als der Aufwand der hochfrequenten Fullscan-Abfragen.

tsteinmaurer 29. Nov 2016 08:45

AW: Index setzen?
 
Zitat:

Also sieht es so aus als ob es genau umgekehrt ist, sobald ich ihn zwinge keinen Index zu verwenden dann wirds schneller!
Habe ich dir in meinem ersten Posting schon gesagt :-D

Bei einem Full-Table-Scan wird dann halt die Response-Time variieren, abhängig davon wie die Caches (OS Filesystem, Firebird Page Cache) befüllt sind. Des weiteren auch, ob Firebird für die implizite Sortieroperation bei einem GROUP BY für temporäre Sachen auf die Disk gehen muss oder alles in den konfigurierten RAM bringt.

Gruber_Hans_12345 29. Nov 2016 09:44

AW: Index setzen?
 
Zitat:

Zitat von tsteinmaurer (Beitrag 1354873)
Zitat:

Also sieht es so aus als ob es genau umgekehrt ist, sobald ich ihn zwinge keinen Index zu verwenden dann wirds schneller!
Habe ich dir in meinem ersten Posting schon gesagt :-D

Bei einem Full-Table-Scan wird dann halt die Response-Time variieren, abhängig davon wie die Caches (OS Filesystem, Firebird Page Cache) befüllt sind. Des weiteren auch, ob Firebird für die implizite Sortieroperation bei einem GROUP BY für temporäre Sachen auf die Disk gehen muss oder alles in den konfigurierten RAM bringt.

Ja stimmt
Für die zeiten führe ich immer zuerst 1-2 mal die Abfrage aus ohne zu messen und dann nehme ich das mittel aus 3-5 abfragen damit ich Last die durch andere verursacht werden nicht so sehr ins Gewicht fallen.

Aber schön das ich endlich mal ein Beispiel finde (aus der Praxis), wo ein Index (der zwar für andere Sachen wichtig ist) so richtig kontraproduktiv ist.

tsteinmaurer 29. Nov 2016 10:12

AW: Index setzen?
 
Beim Testen nicht vergessen, dass auch alle Datensätze gefetched werden und nicht nur Top X, z.b. durch ein Daten-Grid. Das kann den Unterschied Index vs. Full-Table Scan nochmal anders darstellen

NicoDE 29. Nov 2016 15:14

AW: Index setzen?
 
Zitat:

Zitat von tsteinmaurer (Beitrag 1354862)
Die Verwendung eines Index ist nicht immer gleichbedeutend mit schneller.

Ich habe mich nur daran gestört, dass es 'nicht möglich' sein soll :-)
(die vorherigen Beiträge erklären ja sehr ausführlich, ob und wie die Indizes benutzt werden können)


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