In Webanwendungen werden Daten häufig auf mehrere Seiten aufgeteilt, wenn sie Nutzern präsentiert werden. Der Endnutzer erhält eine Seite mit Ergebnissen. Wenn er zur nächsten Seite wechselt, wird die nächste Ergebnismenge abgerufen und angezeigt. Auf dieser Seite wird beschrieben, wie Sie Suchergebnissen bei einer Volltextsuche in Spanner eine Paginierung hinzufügen.
Paginierungsoptionen
Es gibt zwei Möglichkeiten, paginated queries in Spanner zu implementieren: schlüsselbasierte Paginierung (empfohlen) und offsetbasierte Paginierung.
Die schlüsselbasierte Paginierung ist eine Methode zum Abrufen von Suchergebnissen in kleineren, überschaubareren Teilen, die gleichzeitig für konsistente Ergebnisse bei Anfragen sorgt. Eine eindeutige Kennung (der „Schlüssel“) aus dem letzten Ergebnis einer Seite wird als Referenzpunkt verwendet, um die nächsten Ergebnisse abzurufen.
Spanner empfiehlt in der Regel die Verwendung der schlüsselbasierten Paginierung. Die offsetbasierte Paginierung ist zwar einfacher zu implementieren, hat aber zwei erhebliche Nachteile:
- Höhere Abfragekosten: Bei der offsetbasierten Paginierung werden dieselben Ergebnisse wiederholt abgerufen und verworfen, was zu höheren Kosten und einer geringeren Leistung führt.
- Inkonsistente Ergebnisse:Bei paginaten Suchanfragen wird jede Seite in der Regel mit einem anderen Lesezeitstempel abgerufen. Die erste Seite kann beispielsweise aus einer Suchanfrage um 13:00 Uhr stammen und die nächste aus einer Suchanfrage um 13:10 Uhr. Das bedeutet, dass sich die Suchergebnisse zwischen den Suchanfragen ändern können, was zu inkonsistenten Ergebnissen auf den einzelnen Seiten führt.
Bei der schlüsselbasierten Paginierung wird dagegen eine eindeutige Kennung (Schlüssel) aus dem letzten Ergebnis einer Seite verwendet, um die nächsten Ergebnisse abzurufen. So wird sowohl ein effizienter Abruf als auch konsistente Ergebnisse gewährleistet, auch wenn sich die zugrunde liegenden Daten ändern.
Um für Stabilität bei den Seitenergebnissen zu sorgen, könnte die Anwendung alle Abfragen für verschiedene Seiten zum selben Zeitstempel senden. Dies kann jedoch fehlschlagen, wenn die Abfrage die Aufbewahrungsdauer der Version überschreitet (Standardeinstellung: 1 Stunde). Dieser Fehler tritt beispielsweise auf, wenn version_gc
eine Stunde beträgt und der Endnutzer die ersten Ergebnisse um 13:00 Uhr abgerufen und um 15:00 Uhr auf Weiter geklickt hat.
Schlüsselbasierte Paginierung verwenden
Bei der schlüsselbasierten Paginierung wird das letzte Element der vorherigen Seite gespeichert und als Ausgangspunkt für die Abfrage der nächsten Seite verwendet. Dazu muss die Abfrage die in der ORDER BY
-Klausel angegebenen Spalten zurückgeben und die Anzahl der Zeilen mit LIMIT
begrenzen.
Damit die schlüsselbasierte Paginierung funktioniert, müssen die Ergebnisse in der Abfrage nach einer strengen Gesamtreihenfolge sortiert werden. Am einfachsten ist es, eine beliebige Gesamtbewertungsreihenfolge auszuwählen und dann bei Bedarf Spalten für den Fall von Gleichständen hinzuzufügen. In den meisten Fällen ist die Gesamtreihenfolge die Sortierreihenfolge des Suchindexes und die eindeutige Kombination von Spalten ist der Primärschlüssel der Basistabelle.
Mit unserem Beispielschema Albums
sieht die Abfrage für die erste Seite so aus:
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 10;
AlbumId
ist der Tiebreaker, da ReleaseTimestamp
kein Schlüssel ist. Es kann zwei verschiedene Alben mit demselben Wert für ReleaseTimestamp
geben.
Um fortzufahren, führt die Anwendung dieselbe Abfrage noch einmal aus, diesmal jedoch mit einer WHERE
-Klausel, die die Ergebnisse auf die vorherige Seite beschränkt. Die zusätzliche Bedingung muss die Sortierreihenfolge (aufsteigend oder absteigend), den Fall von Gleichständen und die Reihenfolge der NULL-Werte für Spalten mit zulässigen Nullwerten berücksichtigen.
In unserem Beispiel ist AlbumId
die einzige Schlüsselspalte (in aufsteigender Reihenfolge) und darf nicht NULL sein. Die Bedingung lautet daher:
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE (ReleaseTimestamp < @last_page_release_timestamp
OR (ReleaseTimestamp = @last_page_release_timestamp
AND AlbumId > @last_page_album_id))
AND SEARCH(AlbumTitle_Tokens, @p)
ORDER BY ReleaseTimestamp DESC, AlbumId ASC
LIMIT @page_size;
Spanner interpretiert diese Art von Bedingung als suchbar. Das bedeutet, dass Spanner den Index nicht für Dokumente liest, die Sie herausfiltern. Diese Optimierung macht die schlüsselbasierte Paginierung viel effizienter als die offsetbasierte Paginierung.
Offsetbasierte Paginierung verwenden
Bei der offsetbasierten Paginierung werden die LIMIT
- und OFFSET
-Klauseln der SQL-Abfrage verwendet, um Seiten zu simulieren. Der Wert für LIMIT
gibt die Anzahl der Ergebnisse pro Seite an.
Der Wert OFFSET
ist für die erste Seite auf null, für die zweite Seite auf die Seitengröße und für die dritte Seite auf das Doppelte der Seitengröße festgelegt.
Mit der folgenden Abfrage wird beispielsweise die dritte Seite mit einer Seitengröße von 50 abgerufen:
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 50 OFFSET 100;
Verwendungshinweise:
- Die
ORDER BY
-Klausel wird dringend empfohlen, um eine einheitliche Reihenfolge zwischen den Seiten zu gewährleisten. - Verwenden Sie in Produktionsabfragen Abfrageparameter anstelle von Konstanten, um
LIMIT
undOFFSET
anzugeben, damit das Abfrage-Caching effizienter wird. Weitere Informationen finden Sie unter Abfrageparameter.
Nächste Schritte
- Weitere Informationen zum Ranking von Suchergebnissen
- Weitere Informationen zur Teilstringsuche
- Weitere Informationen zum Kombinieren von Volltext- und Nicht-Textabfragen
- Weitere Informationen zur Suche in mehreren Spalten