setFirstResult(startID) vs "...WHERE id>=startID"

Hey hey

Ich wollte in meiner Anwendung ein Paging einbauen und hab mir dazu Methoden gebaut die mit setFirstResult(int startID) und setMaxResult(int id) arbeiten.
Mir is aufgefallen das das setzen des FirstResults mit zunehmender ID Größe deutlich langsamer wird. Die Abfrage mit einer startID=0 ist deutlich schneller als statrID=600000, bei gleichem maxResult.
Zum Testen hab ich dann das ganze in die Query geschrieben “select * from Customer where id>=statrID” und da gibt es bei keiner Zahl Geschwindigkeitseinbußen.

Warum ist das so? Ich dachte das die Methode auch nur auf ein SQL Statement mapped? Oder ist allgemein LIMIT/OFFSET langsamer als über WHERE?

Grüße

hast du ein ORDER BY in der Query oder vertraust du auf die im Grunde beliebig mögliche Rückgabereihenfolge der DB?

in jeden Fall ist der mögliche Unterschied doch abstrakt betrachtet eindeutig:
beim WHERE reicht maximal ein Komplettdurchlauf, durch Indexe besser noch schneller, Auswahl weniger Einträge fürs Ergebnis

bei der startId muss speicherphysikalisch eine neue Liste von 600.000 Einträgen aufgebaut werden,
(mit ORDER BY gar sämtliche Einträge, um erst dann Sortierung zu ermöglichen),
und darauf als zweiten Schritt die Auswahl

dass startID=0 schneller ist als anderes, vielleicht sogar vergleichbar mit einer WHERE-Query, stellt die einfache Sicht etwas in Frage,
aber irgendeine Arbeit wird ja wohl zu tun sein,

vielleicht ist das Erstellen einer sortierten Liste, besonders erstmal nur den Anfang davon, mit Indexen und sonstigen Tricks doch überschaubar,
-> wenn nur diesen Anfang nötig, nicht bis 600.000 hoch zusammenzustellen, dann schnell fertig


was wäre die Alternative, ‘auf ein SQL Statement mapped’?
soll daraus ein bestimmter Id-Berech für ein WHERE berechnet werden? klingt abenteuerlich, nach welcher Vorgabe, weil die Id im ORDER BY steht?
was ist wenn unter den ersten 600.000 Ids 458 nicht vergeben sind, soll dann auch OFFSET=600000 auf Id = 600.458 umgerechnet werden?

eine Id ist wie jedes Attribut beliebige Daten reichlich unbekannten Inhalts,
die Einträge der Tabelle stehten unsortiert beliebig in der DB, es gibt kein Array mit konkreten Index-Positionen oder so,
intern vielleicht, aber nicht für SQL-Auswertung

Zum testen hatte ich in der Tat ein simples “select * from Table”, ohne ORDER BY.

Das das langsamer ist, ist nun nachvollziehbar thx. Was ist dann aber der Vorteil der Methode wenn sie im Grunde nichts besser macht als ein WHERE?

wenn du nicht rein nach eigenen Ids gehts, sondern eine komplexe Query hast (z.B. Suche nach allen Forum-Einträgen von MannOhneNick),
oder auch nur ein kompliziertes ORDER BY auf Einträge mit Id hast (alle Foren-Threads sortiert nach Anzahl Antworten/ Klicks)
dann wird es mit der WHERE-Bedingung schwer :wink:

auch mein genanntes Beispiel mit 458 fehlenden Ids, da müsste man erstmal kompliziert auswerten, was denn Position 600.000 wäre

WHERE ist eben begrenzt auf Unterstützung passender Ids,
wenn man die aber hat, den Hintergrund-Aufwand betrieben hat, idealerweise mit Index unterstützt,
dann ist deren Verwendung dem generischen Arbeits-Ansatz weit überlegen

wie auch ein Cache und immer und überall gilt:
Arbeit im Vorfeld + Einsatz von Speicherplatz zur Ablage von Zusatzinfos spart in der kritischen Phase Arbeit ein

Kann es sein, dass du mit Variante 1 alle Zeilen vor der interessanten „überblätterst“, d.h. durch ein riesiges ResultSet gehst …

und in Variante 2 beim Select „WHERE id>=600000“ die DB bereits ganz schnell ein kleines ResultSet erzeugen lässt, bei dem du sofort anfangen kannst?

Da das eine JPA Methode ist, kann ich darauf nicht endgültig antworten. Nach dem Post von Slater wird es aber sowas sein, ja. Mein Gedanke dabei war irgendwie das in beiden Fällen “nur” eine Art Pointer gesetzt wird, abhängig vom PK. Das es da uU noch dutzende Spezialfälle gibt wo das nicht so einfach ist, war kein Teil des Gedankens .(