La Pagination est dur lorsque votre contenu classement peut changer rapidement, et encore plus difficile lorsque ces classements diffèrent par utilisateur. (Nous allons traiter infini défilement comme un type de pagination, où les liens sont invisibles.) Il y a deux problèmes difficiles: nouveau contenu ajouté en haut, et reranked de contenu.
Oublions nouvellement ajouté de contenu, et d'accepter que vous allez avoir à actualiser la page 1 pour voir. Gardons-nous de prétendre que nous faisons pure, ORDER BY position
; si vous êtes de la commande par quelque chose d'autre, vous pouvez utiliser les fonctions de la fenêtre. Nos pages ont 4 rangées d'animaux par page. Ils commencent à sortir:
+----+----------+-----------+
| id | position^| animal |
+----+----------+-----------+
| 1 | 1 | Alpacas |
| 2 | 2 | Bats |
| 3 | 3 | Cows |
| 4 | 4 | Dogs |
| 5 | 5 | Elephants |
| 6 | 6 | Foxes |
| 7 | 7 | Giraffes |
| 8 | 8 | Horses |
+----+----------+-----------+
Après on va chercher la page 1, et avant de nous extraire de la page 2, un grand nombre d'éléments à déplacer. La DB est maintenant:
+----+----------+-----------+
| id | position^| animal |
+----+----------+-----------+
| 4 | 1 | Dogs |
| 2 | 2 | Bats |
| 1 | 3 | Alpacas |
| 5 | 4 | Elephants |
| 6 | 5 | Foxes |
| 7 | 6 | Giraffes |
| 3 | 7 | Cows |
| 8 | 8 | Horses |
+----+----------+-----------+
Il existe trois approches:
Offset/limite approche
C'est typique de l'approche naïve; dans les Rails, c'est la façon dont will_paginate et Kaminari travail. Si je veux extraire de la page 2, je vais le faire
SELECT * FROM animals
ORDER BY animals.position
OFFSET ((:page_num - 1) * :page_size)
LIMIT :page_size;
qui obtient les lignes 5-8. Je ne vais jamais voir les Éléphants, et je vais voir les Vaches deux fois.
Vu pour la dernière ID approche
Reddit prend une approche différente. Au lieu de calculer la première ligne en fonction de la taille de page, le client suit l'ID du dernier élément que vous avez vu, comme un signet. Lorsque vous appuyez sur "suivant", ils commencent à la recherche de ce signet et les années suivantes:
SELECT * FROM animals
WHERE position > (
SELECT position FROM animals
WHERE id = :last_seen_id
)
ORDER BY position
LIMIT :page_size;
Dans certains cas, cela fonctionne mieux que la page/offset. Mais dans notre cas, les Chiens, le dernier-vu le post, agrandie de droit de #1. Ainsi, le client envoie ?last_seen_id=4
, et ma page 2 est les Chauves-souris, des Alpagas, des Éléphants et des Renards. Je n'ai pas manqué tous les animaux, mais j'ai vu des Chauves-souris et les Alpagas deux fois.
Côté serveur de l'état
HackerNews (et notre site, pour l'instant) résout ce côté serveur continuations; ils stockent l' ensemble de l' ensemble de résultats pour vous (ou au moins plusieurs pages à l'avance?), et le "Plus" références de lien que la continuation. Lorsque j'extrais de la page 2, je demande "à la page 2 de mon original de la requête". Il utilise le même offset/calcul de la limite, mais vu que c'est à l'encontre de la requête d'origine, je n'ai tout simplement pas de soins que les choses ont maintenant déplacé autour de. Je vois des Éléphants, des Renards, des Girafes, et des Chevaux. Pas de dup, pas manquer des éléments.
L'inconvénient est que nous avons à stocker beaucoup de l'état sur le serveur. Sur HN, qui est stocké dans la RAM, et qu'en réalité, ces continuations souvent expire avant que vous pouvez appuyer sur le bouton "Plus", vous forçant à aller tout le chemin du retour à la page 1 de trouver un lien valide. Dans la plupart des applications, vous pouvez la stocker dans memcached, ou même dans la base de données elle-même (à l'aide de votre propre table, ou dans Oracle ou PostgreSQL, à l'aide de holdable les curseurs). Selon votre demande, il pourrait y avoir un gain de performance; dans PostgreSQL, au moins, vous devez trouver un moyen de frapper la bonne connexion de base de données à nouveau, ce qui nécessite beaucoup de collant-état ou astucieux back-end de routage.
Ces trois approches possibles? Si non, est-il de l'ordinateur-les concepts de la science, qui me donnerait à Google de jus de lire à ce sujet? Est-il possible de rapprocher la poursuite de l'approche sans stockage de l'intégralité du jeu de résultats? À Long terme, il y a des événements complexes-streaming/point-à-temps des systèmes, où "le jeu de résultat au moment où je l'ai récupéré à la page 1" est indéfiniment dérivable. Bref de ce que... ?