Offset Pagination dans le développement mobile : ce que c'est et comment l'implémenter

Auteur : IT Sectr Publié le : 2026-03-11 Temps de lecture : 10 min

L'Offset Pagination — pagination par décalage — une méthode de chargement paginé des données via HTTP API. Le client envoie les paramètres offset (décalage depuis le début) et limit (taille de la page), et le serveur retourne les enregistrements à partir de la position offset. Selon le REST API Tutorial, cette approche est largement utilisée dans les services RESTful grâce à sa simplicité d'implémentation. Cependant, sur de grands volumes de données, la pagination par décalage perd en performances en raison du scan complet de la table jusqu'à la position souhaitée.

Points clés

  • Offset Pagination — méthode de pagination où le serveur ignore N enregistrements et retourne les M suivants.
  • La simplicité d'implémentation en fait le standard pour les API REST et les clients mobiles.
  • Problème de sauts — lors de l'insertion d'enregistrements entre les requêtes, l'utilisateur voit des doublons.
  • Décalages dans les données — la suppression d'enregistrements entraîne un décalage des pages et une perte de contenu.
  • La pagination Cursor-based résout ces problèmes grâce à un pointeur vers le dernier enregistrement au lieu d'un décalage.

Qu'est-ce que l'Offset Pagination ?

L'Offset Pagination est une méthode de pagination des données où la requête client contient deux paramètres : offset (combien d'enregistrements ignorer) et limit (combien d'enregistrements retourner). Le serveur exécute une requête SQL avec OFFSET et LIMIT, ignore le nombre spécifié de lignes et retourne un ensemble de résultats de taille fixe.

La méthode est née dans les bases de données relationnelles comme le moyen le plus simple d'organiser la navigation par pages et a été transférée aux API HTTP avec le développement de l'architecture REST. L'Offset Pagination ne nécessite pas de stockage d'état sur le serveur — chaque requête est indépendante et contient toutes les informations nécessaires à la requête.

Selon le rapport de conception d'API de Postman (2025), la pagination par décalage est utilisée dans 72 % des API REST publiques, ce qui en fait le standard dominant malgré les limitations de performances connues sur les grands ensembles de données.

Structure de la requête et de la réponse

Une requête REST typique avec Offset Pagination inclut les paramètres de requête offset et limit. La réponse contient la liste des enregistrements de la page demandée et des métadonnées pour construire l'interface de navigation.

Le paramètre limit limite le nombre d'enregistrements retournés et protège le serveur et le client contre une charge excessive. Les valeurs typiques de limit vont de 10 à 50 enregistrements par page selon la complexité des données.

kotlin
data class PageRequest(
    val offset: Int,
    val limit: Int
)

data class PageResponse<T>(
    val items: List<T>,
    val total: Int,
    val hasMore: Boolean
)

fun RetrofitApi.fetchPage(request: PageRequest): Call<PageResponse<Item>>

Comment fonctionne l'Offset Pagination

L'Offset Pagination se traduit par une requête SQL avec les constructions OFFSET et FETCH NEXT (ou LIMIT dans MySQL/SQLite). Le serveur de base de données scanne la table, ignore le nombre de lignes égal au décalage et retourne les limit lignes suivantes. Plus le décalage est grand, plus la requête est longue.

Le problème de performance vient du fait que la base de données ne peut pas sauter directement à la position du décalage — elle doit lire et jeter toutes les lignes précédentes. Avec offset = 100000 et limit = 20, le SGBD lit 100 020 lignes et n'en retourne que 20.

Requête SQL sous le capot

SQL — le langage dans lequel le serveur exécute la pagination par décalage. PostgreSQL et MySQL utilisent LIMIT, tandis que SQL Server et Oracle utilisent OFFSET...FETCH. Différents SGBD optimisent cette requête différemment, mais le problème fondamental de scan reste le même.

sql
SELECT id, title, created_at
FROM articles
ORDER BY created_at DESC
OFFSET 100000 ROWS
FETCH NEXT 20 ROWS ONLY;

Problème de cohérence

La cohérence des données est le principal inconvénient de l'Offset Pagination lors du travail avec des ensembles dynamiques. Si un nouvel enregistrement est ajouté au début de la table entre deux requêtes utilisateur, tous les enregistrements existants se décalent. L'utilisateur voit des doublons ou des lacunes.

Prenons une table de 100 enregistrements avec limit = 20. Sur la page 1, l'utilisateur voit les enregistrements 1-20. Un administrateur ajoute 5 nouveaux enregistrements. Sur la page 2, l'utilisateur voit les enregistrements 26-45 au lieu des 21-40 attendus — les enregistrements 21-25 sont ignorés, et les enregistrements 21-25 de l'ensemble précédent sont dupliqués sur la page 1.

Offset vs Cursor-based : comparaison des approches

La pagination Cursor-based est une alternative à l'Offset Pagination qui utilise un pointeur vers le dernier enregistrement de la page courante. Au lieu d'un décalage numérique, le client envoie l'identifiant du dernier enregistrement reçu, et le serveur retourne les N enregistrements suivants après celui-ci.

L'approche cursor-based résout le problème de cohérence : la position du curseur ne change pas lors des insertions ou suppressions car le curseur fait référence à un enregistrement spécifique, pas à une position. Cependant, elle est plus complexe à implémenter — elle nécessite un champ unique triable (généralement ID ou timestamp).

ParamètreOffset PaginationCursor-based Pagination
SimplicitéÉlevée — deux paramètres numériquesMoyenne — encodage du curseur requis
CohérenceFaible — doublons lors des insertionsÉlevée — curseur non affecté par les changements
PerformancesSe dégrade avec un grand offsetStables quel que soit le volume
Saut de pageOui — peut naviguer vers n'importe quelle pageNon — navigation séquentielle uniquement
Idéal pourTables <10K enregistrements, UI avec numéros de pageFlux, défilement infini, grands ensembles

Le choix entre les approches dépend des exigences de l'interface utilisateur. Si une navigation avec numéros de page et saut direct est nécessaire — l'Offset Pagination est plus simple. Pour le défilement infini ou les flux d'actualités, les curseurs sont préférables.

Keyset pagination

La Keyset pagination est une variante de l'approche cursor-based où le filtrage est effectué sur une clé unique en utilisant WHERE au lieu d'OFFSET. La requête SQL utilise une condition comme WHERE id > lastId, permettant à la base de données d'utiliser un index sans scanner les lignes ignorées.

Selon le Wiki PostgreSQL, la keyset pagination s'exécute 100 à 1000 fois plus rapidement que les requêtes offset pour les grands décalages, car le scan d'index remplace le scan complet de table. L'inconvénient est l'impossibilité de sauter vers une page arbitraire sans parcours séquentiel.

Quand utiliser l'Offset Pagination

L'Offset Pagination est optimale pour les ensembles de données petits et moyens (jusqu'à 10 000 enregistrements) où l'utilisateur a besoin d'une interface avec numéros de page. Les scénarios typiques incluent les panneaux d'administration, les listes de commandes et les catalogues filtrés avec pagination par pages.

Pour les applications mobiles, la pagination par décalage est adaptée lors du chargement de données historiques où les nouvelles insertions sont rares ou impossibles — par exemple, l'historique des commandes utilisateur, les listes de tâches terminées ou les archives de transactions. Dans ces scénarios, le problème de cohérence ne se pose pas.

Non recommandée pour les flux de réseaux sociaux, les listes de commentaires, les chats et autres ensembles dynamiques avec insertions fréquentes. Dans ces cas, les lacunes et les enregistrements en double dégradent l'expérience utilisateur et nécessitent une logique de déduplication supplémentaire sur le client.

Approche hybride

La pagination hybride combine offset et curseur : la première requête utilise l'offset pour afficher la page initiale, tandis que les requêtes suivantes utilisent le curseur pour le chargement par défilement infini. Cette approche est utilisée sur Instagram et Twitter, où la première page est chargée via un curseur, mais l'offset est utilisé pour calculer la position lors du retour à une vue précédente.

Implémenter une approche hybride nécessite de stocker la position virtuelle de l'utilisateur sur le client et de coordonner deux mécanismes de pagination sur le serveur. Selon le blog Instagram Engineering, leur équipe utilise la pagination cursor-based avec un champ supplémentaire startCursor qui remplace l'offset pour le chargement initial.

Offset Pagination dans les applications mobiles

Les applications mobiles utilisent l'Offset Pagination avec Retrofit/OkHttp sur Android et URLSession/Combine sur iOS. Le motif typique est le chargement de la page suivante lors du défilement vers la fin de la liste via RecyclerView.OnScrollListener ou le préchargement UICollectionView.

L'implémentation de la pagination par décalage sur un client mobile comprend trois composants : un gestionnaire de pagination (stocke l'offset actuel et hasMore), un adaptateur de liste (affiche les éléments et l'indicateur de chargement) et un référentiel (exécute les requêtes et gère les erreurs). Android Jetpack propose la bibliothèque Paging 3, qui prend en charge à la fois la pagination par offset et par curseur prête à l'emploi.

Implémentation en Kotlin avec Paging 3

Paging 3 est une bibliothèque Android Jetpack pour le chargement paginé de données. Elle encapsule la logique de pagination, y compris le suivi de l'offset, la gestion de l'état de chargement et le préchargement automatique lors du défilement. PagingSource définit les clés pour les pages suivante et précédente.

kotlin
class OffsetPagingSource(
    private val api: ApiService,
    private val limit: Int = 20
) : PagingSource<Int, Item>() {

    override suspend fun load(
        params: LoadParams<Int>
    ): LoadResult<Int, Item> {
        val offset = params.key ?: 0
        return try {
            val response = api.getItems(offset, limit)
            LoadResult.Page(
                data = response.items,
                prevKey = null,
                nextKey = if (response.hasMore) offset + limit else null
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
}

PagingSource définit les clés prevKey et nextKey pour la navigation entre les pages. Avec la pagination par offset, prevKey est toujours null (impossible d'aller à la page précédente sans sauvegarder l'historique), tandis que nextKey augmente de limit à chaque chargement jusqu'à ce que le serveur retourne hasMore = false. C'est un modèle simple et prévisible pour les listes mobiles.

Erreurs courantes avec l'Offset Pagination

Première erreur — se fier à l'ordre des enregistrements sans tri. L'Offset Pagination exige un tri ORDER BY stable sur un champ unique. Sans cela, le SGBD peut retourner les enregistrements dans un ordre arbitraire, entraînant des doublons et des lacunes aléatoires entre les pages.

Deuxième erreur — utiliser l'offset pour calculer le numéro de page dans l'interface. La formule page = offset / limit + 1 fonctionne uniquement si aucun enregistrement n'a été supprimé ou ajouté entre les chargements. Avec des données dynamiques, le numéro de page devient inexact et l'utilisateur voit des informations incorrectes.

Troisième erreur — ignorer les timeouts des requêtes avec un grand offset. Avec un offset supérieur à 100 000, la requête peut prendre des dizaines de secondes, bloquant l'interface et consommant les ressources du serveur. Il est recommandé de définir une valeur maximale d'offset au niveau de l'API (par exemple, 10 000) et d'utiliser la pagination cursor-based pour les grands volumes.

Quatrième erreur — ne pas inclure le total count dans la réponse. Sans le nombre total d'enregistrements, le client ne peut pas afficher le nombre de pages ni implémenter une pagination numérotée. Cependant, COUNT(*) sur les grandes tables est coûteux — pour les ensembles de plus de 100 000 enregistrements, utilisez des estimations approximatives ou limitez la valeur maximale du total.

Questions fréquentes

En quoi l'Offset Pagination diffère-t-elle du Cursor-based ?

L'Offset utilise un décalage numérique pour ignorer les enregistrements, tandis que le curseur utilise un pointeur vers le dernier enregistrement de la page précédente. L'Offset est plus simple à implémenter mais souffre de doublons lors des insertions et de perte de performance sur les grands décalages. Le curseur est stable quels que soient les changements de données.

Quand l'Offset Pagination a-t-elle de mauvaises performances ?

La pagination par offset est inefficace pour des offsets supérieurs à 10 000 enregistrements en raison du scan complet de la table. Elle est également inadaptée aux ensembles dynamiques (flux, chats) où de nouveaux enregistrements apparaissent entre les requêtes — l'utilisateur voit des lacunes et des enregistrements en double lors de la navigation.

Quel limit est optimal pour l'Offset Pagination ?

Le limit optimal dépend de la taille de l'enregistrement et de la vitesse du réseau — de 10 à 50 éléments par page. Pour les listes avec de grandes images, utilisez limit = 10-15 ; pour les données textuelles, 20-50. Autorisez toujours le client à spécifier son propre limit avec un maximum côté serveur (généralement 100).

Comment gérer les doublons avec l'Offset Pagination ?

Pour gérer les doublons, utilisez la déduplication côté client par ID unique, appliquez un tri stable sur un champ unique ou passez à la pagination cursor-based. Android Paging 3 prend en charge la key pour la déduplication automatique des éléments de liste.

Peut-on utiliser l'Offset Pagination avec GraphQL ?

Oui, GraphQL prend en charge la pagination par offset via les arguments offset et limit dans la requête, bien que la spécification Relay recommande l'approche cursor-based. Les bibliothèques Apollo GraphQL et Relay offrent une prise en charge intégrée de la pagination par offset avec gestion automatique de l'état des pages.

Résumé

  • Offset Pagination — méthode de pagination avec des paramètres offset et limit pour ignorer et limiter les enregistrements lors du chargement paginé de données depuis une API.
  • La simplicité d'implémentation et l'indépendance des requêtes font de l'Offset Pagination l'approche standard pour 72 % des API REST (données Postman, 2025).
  • Les performances se dégradent pour les offsets supérieurs à 10 000 en raison du scan de la table jusqu'à la position cible — la base de données lit toutes les lignes ignorées.
  • Problème de cohérence — les insertions et suppressions d'enregistrements entre les requêtes entraînent des doublons et des lacunes dans les résultats des pages.
  • La pagination Cursor-based résout les problèmes de l'Offset Pagination en utilisant un pointeur vers le dernier enregistrement au lieu d'un décalage numérique.
  • L'approche hybride combine l'offset de la première page avec le chargement par curseur pour le défilement infini dans les applications mobiles.
  • Recommandation — utilisez l'Offset Pagination pour les ensembles statiques jusqu'à 10 000 enregistrements et passez aux curseurs pour les grands volumes et les données dynamiques.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi