Der beste Weg, die fortlaufende Liste mit PostgreSQL im Web zu holen

8

Ich mache API über HTTP, die große Zeilen von PostgreSQL mit Seitenumbruch abruft. In normalen Fällen implementiere ich Paginierungen normalerweise über naive OFFET / LIMIT -Klausel. Es gibt jedoch einige spezielle Anforderungen in diesem Fall:

  • Viele Zeilen gibt es, aber ich glaube, dass die Benutzer das Ende nicht erreichen können (stell dir die Timeline von Twitter vor).
  • Seiten müssen nicht zufällig, sondern sequentiell zugänglich sein.
  • Die API gibt eine URL zurück, die ein Cursor-Token enthält, das auf die Seite mit fortlaufenden Stücken verweist.
  • Cursor-Token müssen nicht dauerhaft existieren, sondern für einige Zeit.
  • Seine Reihenfolge hat häufig fluktuierende (wie Reddit-Rankings), aber kontinuierliche Cursor sollten ihre konsistente Reihenfolge beibehalten.

Wie kann ich die Mission erreichen? Ich bin bereit, mein ganzes Datenbankschema dafür zu ändern!

    
minhee 12.10.2011, 21:37
quelle

2 Antworten

6

Wenn man annimmt, dass nur die Reihenfolge der Ergebnisse schwankt und nicht die Daten in den Zeilen, ist Fredriks Antwort sinnvoll. Ich würde jedoch die folgenden Ergänzungen vorschlagen:

  • Speichern Sie die ID-Liste in einer postgresql-Tabelle mit dem Array -Typ und nicht im Speicher. Wenn Sie im Speicher arbeiten, sollten Sie sich auf DOS-Speicherverbrauchsangriffe einstellen, es sei denn, Sie verwenden etwas wie Redis mit automatischem Ablauf und Speicherbegrenzungen. Ich stelle mir vor, dass es ungefähr so ​​aussehen würde:

    %Vor%
  • Sie müssen entscheiden, ob cursor_token und result_ids von Benutzern gemeinsam genutzt werden können, um die Speicheranforderungen und die Zeit zu verringern, die für die Ausführung der ersten Abfrage pro Benutzer erforderlich ist. Wenn sie freigegeben werden können, wählen Sie ein Cache-Fenster, sagen Sie 1 oder 5 Minute (n), und erstellen Sie dann nach einer neuen Anfrage das Cache_Token für diesen Zeitraum und prüfen Sie, ob die Ergebnis-IDs bereits für dieses Token berechnet wurden. Wenn nicht, füge eine neue Zeile für dieses Token hinzu. Sie sollten wahrscheinlich eine Sperre um den Prüf- / Einfügecode hinzufügen, um gleichzeitige Anforderungen für ein neues Token zu bearbeiten.

  • Haben Sie einen geplanten Hintergrundjob, der alte Token / Ergebnisse bereinigt und sicherstellt, dass Ihr Client-Code alle Fehler im Zusammenhang mit abgelaufenen / ungültigen Tokens verarbeiten kann.

Denken Sie nicht einmal daran, echte db-Cursor dafür zu verwenden.

Das Speichern der Ergebnis-IDs in Redis-Listen ist eine andere Möglichkeit, dies zu umgehen (siehe LRANGE -Befehl), aber seien Sie vorsichtig beim Ablauf und Speicherverbrauch, wenn Sie diesen Pfad gehen. Ihre Redis-Taste wäre das cursor_token und die IDs wären die Mitglieder der Liste.

    
Tavis Rudd 19.10.2011, 21:44
quelle
1

Ich weiß absolut nichts über PostgreSQL, aber ich bin ein ziemlich anständiger SQL Server-Entwickler, also würde ich gerne einen Blick darauf werfen:)

Wie viele Zeilen / Seiten erwarten Sie, dass ein Benutzer maximal pro Sitzung durchsucht werden kann? Wenn Sie zum Beispiel erwarten, dass ein Benutzer für jede Sitzung maximal 10 Seiten durchsucht (jede Seite enthält 50 Zeilen), können Sie diesen Maximalwert verwenden und den Webservice so einrichten, dass der Cache zwischengespeichert wird, wenn der Benutzer die erste Seite anfordert 10 * 50 Zeilen (oder nur die Id: s für die Zeilen, hängt davon ab, wie viel Speicher / gleichzeitige Benutzer Sie bekommen haben).

Dies würde sicherlich dazu beitragen, Ihren Webservice in mehr als einer Hinsicht zu beschleunigen. Und es ist ziemlich einfach zu implementieren. Also:

  • Wenn ein Benutzer Daten von Seite 1 anfordert. Führen Sie eine Abfrage aus (komplett mit order by, joinchecks usw.), speichern Sie alle id: s in einem Array (aber maximal 500 IDs). Gibt Datenarrays zurück, die IDs im Array an den Positionen 0-9 entsprechen.
  • Wenn der Benutzer Seite 2-10 anfordert. Zurückgeben von Datenzeilen, die ids im Array an Positionen entsprechen (Seite-1) * 50 - (Seite) * 50-1.

Sie könnten auch die Zahlen erhöhen, ein Array von 500 int: s würde nur 2K Speicher belegen, aber es hängt auch davon ab, wie schnell Sie Ihre anfängliche Abfrage / Antwort wollen.

Ich habe eine ähnliche Technik auf einer Live-Website verwendet, und als der Benutzer auf Seite 10 weiterging, wechselte ich einfach zu Abfragen. Ich denke, eine andere Lösung wäre, das Array weiter zu erweitern / zu füllen. (Die Abfrage erneut ausführen, aber die bereits eingeschlossene ID ausschließen: s).

Wie auch immer, hoffe das hilft!

    
Fredrik Johansson 15.10.2011 04:47
quelle