Mysql
 sql >> Base de données >  >> RDS >> Mysql

mySQL - Pagination des lignes filtrées

Vous ne pouvez pas savoir quel est le premier identifiant sur une page donnée, car les numéros d'identifiant ne sont pas nécessairement séquentiels. En d'autres termes, il pourrait y avoir des lacunes dans la séquence, de sorte que les lignes de la cinquième page de 100 lignes ne commencent pas nécessairement à l'id 500. Cela pourrait commencer à l'id 527 par exemple, c'est impossible à savoir.

En d'autres termes :id est une valeur, pas un numéro de ligne.

Une solution possible si votre client avance dans les pages dans l'ordre croissant est que chaque requête REST récupère les données, note la plus grande valeur d'identifiant sur cette page, puis l'utilise dans la suivante Requête REST pour qu'il interroge les valeurs d'identifiant qui sont plus grandes.

SELECT ... FROM ... WHERE filterKey = filterValue 
AND id > id_of_last_match_of_previous_page

Mais si votre requête REST peut récupérer n'importe quelle page aléatoire, cette solution ne fonctionne pas. Cela dépend du fait que vous ayez déjà récupéré la page précédente.

Une autre solution consiste à utiliser le LIMIT <x> OFFSET <y> syntaxe. Cela vous permet de demander n'importe quelle page arbitraire. LIMIT <y>, <x> fonctionne de la même manière, mais pour une raison quelconque, x et y sont inversés dans les deux formes de syntaxe différentes, alors gardez cela à l'esprit.

Utilisation de LIMIT...OFFSET n'est pas très efficace lorsque vous demandez une page contenant plusieurs pages dans le résultat. Supposons que vous demandiez la 5 000e page. MySQL doit générer un résultat côté serveur de 5 000 pages, puis en supprimer 4 999 et renvoyer la dernière page du résultat. Désolé, mais c'est comme ça que ça marche.

Concernant votre commentaire :

Vous devez comprendre que WHERE applique des conditions sur les valeurs en lignes, mais les pages sont définies par la position de rangées. Ce sont deux manières différentes de déterminer les lignes !

Si vous avez une colonne qui est garantie d'être un numéro de ligne , vous pouvez utiliser cette valeur comme une position de ligne. Vous pouvez même y mettre un index ou l'utiliser comme clé primaire.

Mais les valeurs de clé primaire peuvent changer et ne pas être consécutives, par exemple si vous mettez à jour ou supprimez des lignes, ou annulez certaines transactions, etc. Renuméroter les valeurs de clé primaire est une mauvaise idée car d'autres tables ou données externes peuvent faire référence à des valeurs de clé primaire.

Vous pouvez donc ajouter une autre colonne qui n'est pas la clé primaire, mais seulement un numéro de ligne.

ALTER TABLE MyTable ADD COLUMN row_number BIGINT UNSIGNED, ADD KEY (row_number);

Remplissez ensuite les valeurs lorsque vous devez renuméroter les lignes.

SET @row := 0;
UPDATE MyTable SET row_number = (@row := @row + 1) ORDER BY id;

Vous devrez renuméroter les lignes si jamais vous en supprimez, par exemple. Il n'est pas efficace de le faire fréquemment, selon la taille de la table.

De plus, les nouvelles insertions ne peuvent pas créer de valeurs de numéro de ligne correctes sans verrouiller la table. Ceci est nécessaire pour éviter les conditions de concurrence.

Si vous avez la garantie que row_number est une séquence de valeurs consécutives, alors c'est à la fois une valeur et une position de ligne, vous pouvez donc l'utiliser pour des recherches d'index hautes performances pour n'importe quelle page arbitraire de lignes.

SELECT * FROM MyTable WHERE row_number BETWEEN 401 AND 500;

Au moins jusqu'à la prochaine fois que la séquence des numéros de lignes est remise en question par une suppression ou par de nouvelles insertions.