Offset Pagination no desenvolvimento mobile: o que é e como implementar

Autor: IT Sectr Publicado: 2026-03-11 Tempo de leitura: 10 min

Offset Pagination — paginação com deslocamento — método de carregamento paginado de dados via HTTP API. O cliente envia os parâmetros offset (deslocamento desde o início) e limit (tamanho da página), e o servidor retorna os registros a partir da posição offset. De acordo com o REST API Tutorial, essa abordagem é amplamente usada em serviços RESTful devido à simplicidade de implementação. No entanto, em grandes volumes de dados, a paginação offset perde desempenho devido à varredura completa da tabela até a posição desejada.

Principais pontos

  • Offset Pagination — método de paginação onde o servidor pula N registros e retorna os próximos M.
  • Simplicidade de implementação o torna o padrão para REST APIs e clientes mobile.
  • Problema de pulos — ao inserir registros entre requisições, o usuário vê duplicatas.
  • Deslocamentos nos dados — a exclusão de registros causa deslocamento de páginas e perda de conteúdo.
  • A paginação Cursor-based resolve esses problemas através de um ponteiro para o último registro em vez de um deslocamento.

O que é Offset Pagination?

Offset Pagination é um método de paginação de dados onde a requisição do cliente contém dois parâmetros: offset (quantos registros pular) e limit (quantos registros retornar). O servidor executa uma consulta SQL com OFFSET e LIMIT, pula a quantidade especificada de linhas e retorna um conjunto de resultados de tamanho fixo.

O método originou-se em bancos de dados relacionais como a forma mais simples de organizar a navegação por páginas e foi transferido para APIs HTTP junto com o desenvolvimento da arquitetura REST. Offset Pagination não requer armazenamento de estado no servidor — cada requisição é independente e contém todas as informações necessárias para a consulta.

De acordo com o relatório de design de API da Postman (2025), a paginação offset é usada em 72% das APIs REST públicas, tornando-a o padrão dominante apesar das limitações conhecidas de desempenho em grandes conjuntos de dados.

Estrutura de requisição e resposta

Uma requisição REST típica com Offset Pagination inclui os parâmetros de consulta offset e limit. A resposta contém a lista de registros da página solicitada e metadados para construir a interface de navegação.

O parâmetro limit restringe a quantidade de registros retornados e protege o servidor e o cliente de cargas excessivas. Os valores típicos de limit variam de 10 a 50 registros por página dependendo da complexidade dos dados.

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>>

Como funciona o Offset Pagination

Offset Pagination se traduz em uma consulta SQL com as construções OFFSET e FETCH NEXT (ou LIMIT no MySQL/SQLite). O servidor de banco de dados varre a tabela, pula a quantidade de linhas igual ao offset e retorna as próximas limit linhas. Quanto maior o offset, mais lenta a consulta.

O problema de desempenho decorre do fato de que o banco de dados não pode pular diretamente para a posição do offset — ele deve ler e descartar todas as linhas anteriores. Com offset = 100000 e limit = 20, o DBMS lê 100.020 linhas e retorna apenas 20.

Consulta SQL por baixo dos panos

SQL — a linguagem na qual o servidor executa a paginação offset. PostgreSQL e MySQL usam LIMIT, enquanto SQL Server e Oracle usam OFFSET...FETCH. Diferentes DBMSs otimizam essa consulta de maneiras distintas, mas o problema fundamental de varredura permanece o mesmo.

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

Problema de consistência

A consistência de dados é a principal desvantagem do Offset Pagination ao trabalhar com conjuntos dinâmicos. Se um novo registro for adicionado ao início da tabela entre duas requisições do usuário, todos os registros existentes se deslocam. O usuário vê duplicatas ou lacunas.

Considere uma tabela de 100 registros com limit = 20. Na página 1, o usuário vê os registros 1-20. Um administrador adiciona 5 novos registros. Na página 2, o usuário vê os registros 26-45 em vez dos esperados 21-40 — os registros 21-25 são pulados, e os registros 21-25 do conjunto anterior são duplicados na página 1.

Offset vs Cursor-based: comparação de abordagens

A paginação Cursor-based é uma alternativa ao Offset Pagination que usa um ponteiro para o último registro da página atual. Em vez de um deslocamento numérico, o cliente envia o identificador do último registro recebido, e o servidor retorna os próximos N registros após ele.

A abordagem cursor-based resolve o problema de consistência: a posição do cursor não muda com inserções ou exclusões porque o cursor se refere a um registro específico, não a uma posição. No entanto, é mais complexa de implementar — requer um campo único ordenável (geralmente ID ou timestamp).

ParâmetroOffset PaginationCursor-based Pagination
SimplicidadeAlta — dois parâmetros numéricosMédia — requer codificação do cursor
ConsistênciaBaixa — duplicatas em inserçõesAlta — cursor não afetado por alterações
DesempenhoDegrada com offset grandeEstável em qualquer volume
Salto para páginaSim — pode navegar para qualquer páginaNão — apenas navegação sequencial
Ideal paraTabelas <10K registros, UI com números de páginaFeeds, scroll infinito, grandes conjuntos

A escolha entre abordagens depende dos requisitos de interface do usuário. Se for necessária navegação com números de página e salto direto — Offset Pagination é mais simples. Para scroll infinito ou feeds de notícias, cursores são preferíveis.

Keyset pagination

Keyset pagination é uma variação da abordagem cursor-based onde a filtragem é realizada em uma chave única usando WHERE em vez de OFFSET. A consulta SQL usa uma condição como WHERE id > lastId, permitindo que o banco de dados use um índice sem varrer linhas descartadas.

De acordo com a Wiki do PostgreSQL, keyset pagination é executada 100-1000 vezes mais rápido que consultas offset em grandes deslocamentos porque a varredura de índice substitui a varredura completa da tabela. A desvantagem é a impossibilidade de pular para uma página arbitrária sem percurso sequencial.

Quando usar Offset Pagination

Offset Pagination é ideal para conjuntos de dados pequenos e médios (até 10.000 registros) onde o usuário precisa de uma interface com números de página. Os cenários típicos incluem painéis de administração, listas de pedidos e catálogos filtrados com paginação por páginas.

Para aplicativos móveis, a paginação offset é adequada ao carregar dados históricos onde novas inserções são raras ou impossíveis — por exemplo, histórico de pedidos do usuário, listas de tarefas concluídas ou arquivos de transações. Nesses cenários, o problema de consistência não surge.

Não recomendado para feeds de redes sociais, listas de comentários, chats e outros conjuntos dinâmicos com inserções frequentes. Nesses casos, lacunas e registros duplicados degradam a experiência do usuário e exigem lógica adicional de deduplicação no cliente.

Abordagem híbrida

A paginação híbrida combina offset e cursor: a primeira requisição usa offset para mostrar a página inicial, enquanto as requisições subsequentes usam cursor para carregamento de scroll infinito. Essa abordagem é usada no Instagram e Twitter, onde a primeira página é carregada via cursor, mas o offset é usado para calcular a posição ao retornar a uma visualização anterior.

Implementar uma abordagem híbrida requer armazenar a posição virtual do usuário no cliente e coordenar dois mecanismos de paginação no servidor. De acordo com o blog Instagram Engineering, sua equipe usa paginação cursor-based com um campo adicional startCursor que substitui o offset para o carregamento inicial.

Offset Pagination em aplicativos móveis

Os aplicativos móveis usam Offset Pagination junto com Retrofit/OkHttp no Android e URLSession/Combine no iOS. O padrão típico é carregar a próxima página ao rolar até o final da lista através de RecyclerView.OnScrollListener ou UICollectionView prefetching.

A implementação de paginação offset em um cliente móvel inclui três componentes: um gerenciador de paginação (armazena o offset atual e hasMore), um adaptador de lista (exibe itens e indicador de carregamento) e um repositório (executa requisições e lida com erros). O Android Jetpack oferece a biblioteca Paging 3, que suporta tanto paginação offset quanto cursor-based nativamente.

Implementação em Kotlin com Paging 3

Paging 3 é uma biblioteca Android Jetpack para carregamento paginado de dados. Ela encapsula a lógica de paginação, incluindo rastreamento de offset, gerenciamento de estado de carregamento e pré-carregamento automático ao rolar. PagingSource define as chaves para as próximas e anteriores páginas.

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 define as chaves prevKey e nextKey para navegação entre páginas. Com paginação offset, prevKey é sempre null (não é possível ir para a página anterior sem salvar histórico), enquanto nextKey aumenta em limit a cada carregamento até que o servidor retorne hasMore = false. Este é um modelo simples e previsível para listas móveis.

Erros comuns no Offset Pagination

Primeiro erro — confiar na ordem dos registros sem ordenação. Offset Pagination requer uma ordenação ORDER BY estável em um campo único. Sem ela, o DBMS pode retornar registros em ordem arbitrária, causando duplicatas e lacunas aleatórias entre páginas.

Segundo erro — usar offset para calcular o número da página na interface. A fórmula page = offset / limit + 1 só funciona se nenhum registro foi excluído ou adicionado entre carregamentos. Com dados dinâmicos, o número da página se torna impreciso e o usuário vê informações incorretas.

Terceiro erro — ignorar os timeouts de consultas com offset grande. Com offset acima de 100.000, a consulta pode levar dezenas de segundos, bloqueando a interface e consumindo recursos do servidor. Recomenda-se definir um valor máximo de offset no nível da API (por exemplo, 10.000) e usar paginação cursor-based para grandes volumes.

Quarto erro — não incluir o total count na resposta. Sem o número total de registros, o cliente não pode exibir a contagem de páginas nem implementar paginação numerada. No entanto, COUNT(*) em tabelas grandes é caro — para conjuntos com mais de 100.000 registros, use estimativas aproximadas ou limite o valor máximo de total.

Perguntas frequentes

Como o Offset Pagination difere do Cursor-based?

Offset usa um deslocamento numérico para pular registros, enquanto cursor usa um ponteiro para o último registro da página anterior. Offset é mais simples de implementar, mas sofre com duplicatas em inserções e perda de desempenho em grandes deslocamentos. Cursor é estável sob quaisquer alterações de dados.

Quando o Offset Pagination tem baixo desempenho?

A paginação offset é ineficiente com offsets acima de 10.000 registros devido à varredura completa da tabela. Também é inadequada para conjuntos dinâmicos (feeds, chats) onde novos registros aparecem entre requisições — o usuário vê lacunas e registros duplicados durante a navegação.

Qual limit é ideal para Offset Pagination?

O limit ideal depende do tamanho do registro e da velocidade da rede — de 10 a 50 itens por página. Para listas com imagens grandes, use limit = 10-15; para dados textuais, 20-50. Sempre permita que o cliente especifique seu próprio limit com um limite máximo no servidor (geralmente 100).

Como lidar com duplicatas no Offset Pagination?

Para lidar com duplicatas, use deduplicação no cliente por ID único, aplique ordenação estável em um campo único ou mude para paginação cursor-based. O Android Paging 3 suporta key para deduplicação automática de itens de lista.

Pode-se usar Offset Pagination com GraphQL?

Sim, GraphQL suporta paginação offset através dos argumentos offset e limit na consulta, embora a especificação Relay recomende a abordagem cursor-based. As bibliotecas Apollo GraphQL e Relay oferecem suporte integrado para paginação offset com gerenciamento automático de estado de páginas.

Resumo

  • Offset Pagination — método de paginação com parâmetros offset e limit para pular e limitar registros durante o carregamento paginado de dados de uma API.
  • A simplicidade de implementação e a independência das requisições tornam o Offset Pagination a abordagem padrão para 72% das APIs REST (dados da Postman, 2025).
  • O desempenho degrada com offsets acima de 10.000 devido à varredura da tabela até a posição alvo — o banco de dados lê todas as linhas descartadas.
  • Problema de consistência — inserções e exclusões de registros entre requisições causam duplicatas e lacunas nos resultados das páginas.
  • A paginação Cursor-based resolve os problemas do Offset Pagination usando um ponteiro para o último registro em vez de um deslocamento numérico.
  • A abordagem híbrida combina o offset da primeira página com carregamento por cursor para scroll infinito em aplicativos móveis.
  • Recomendação — use Offset Pagination para conjuntos estáticos de até 10.000 registros e mude para cursores para grandes volumes e dados dinâmicos.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também