Pular para o conteúdo
Backend

Paginação Offset vs Cursor: Performance e Melhores Práticas no SQL

As diferenças e impactos reais das estratégias Offset-based e Cursor-based Pagination para bases de dados grandes. escolher a abordagem ideal em cada cenário e melhore a performance das

Por que isso é importante

Paginação: cursor para escala — offset em feed quente vira bug de página fantasma.

O que é Offset-Based Pagination?

O modelo Offset-Based Pagination utiliza os comandos OFFSET e LIMIT nas queries para
retornar apenas um subconjunto de registros, permitindo navegar entre "páginas" de dados
com facilidade. Por exemplo, ao consultar a página 2 com 10 itens por página, você faz
OFFSET 10 LIMIT 10, pulando os 10 primeiros e pegando os próximos 10 resultados.

Atenção

Apesar de ser simples e bastante utilizado, o OFFSET não reduz a quantidade de
registros consultados internamente pelo banco – apenas os registros retornados para o
cliente.

Por que o OFFSET traz problemas de performance?

Quando se trabalha com tabelas que possuem milhões de registros, o banco precisa
percorrer (e processar) todos os registros até o número do OFFSET antes de retornar o
resultado solicitado. Isso faz com que consultas em páginas distantes da primeira
aumentem exponencialmente em tempo de execução e uso de memória, tornando o processo
cada vez mais lento e custoso.

Atenção

Em cenários de paginação profunda (ex: OFFSET 1.000.000), o banco pode demorar vários
segundos para responder e gerar alto consumo de CPU e RAM, afetando outros processos e
a saúde do sistema como um todo.

Comportamento Interno do OFFSET no SQL

Diferente do WHERE, que filtra registros logo no início da execução da query, o OFFSET
apenas pula os resultados já processados. Isso significa que, para OFFSET 500 LIMIT 20,
o banco busca os 520 registros e só retorna os 20 após o 500º, ao invés de simplesmente
limitar a consulta desde o começo.

Atenção

OFFSET não indica ao banco de dados quais linhas exatamente ignorar em relação à
ordenação do resultado, pois o banco não guarda referência sequencial dos registros
consultados.

Quando usar Offset-Based Pagination de forma segura

Offset-Based Pagination é suficiente e eficiente quando você trabalha com um volume
pequeno ou moderado de dados (centenas a poucos milhares de registros), onde o overhead
de ignorar múltiplos registros não afeta significativamente o desempenho. Também é útil
quando a navegação direta entre páginas exatas é importante para o usuário.

  1. Passo 1: Analise o tamanho máximo da sua tabela antes de optar
    por OFFSET.
  2. Passo 2: Considere a necessidade de navegação direta entre
    páginas.
  3. Passo 3: Utilize índices para garantir que o ORDER BY acompanhe
    o OFFSET de modo eficiente.

Paginação com Scroll Infinito: o que muda?

Em interfaces modernas, cada vez mais comuns são as listas com carregamento contínuo
(scroll infinito), como exemplos do Twitter e Instagram. Nesses casos, o usuário não
seleciona páginas, mas carrega os itens seguintes conforme rola a tela. Aqui, a
abordagem com OFFSET rapidamente se torna ineficiente.

Entrada do Cursor-Based Pagination

Cursor-Based Pagination utiliza um campo ordenável do registro (ex: ID sequencial ou
data de publicação) como referência para buscar novos elementos, usando um WHERE ao
invés de OFFSET. Assim, ao buscar a próxima "página" de dados, só são buscados registros
após o último exibido, aumentando a performance drasticamente, especialmente em grandes
volumes.

Como funciona Cursor-Based Pagination

Em vez de pular um número fixo de registros, você envia o valor do último campo
ordenável exibido (como o ID ou data) como cursor para a próxima consulta. Por exemplo,
WHERE id > 400, LIMIT 20. Assim, só os registros após o último são trazidos, sem
custo extra de leitura de dados.

  1. Passo 1: Escolha um campo único e ordenável da sua tabela.
  2. Passo 2: Use o valor do último item retornado em cada
    carregamento como cursor para a próxima busca.
  3. Passo 3: Implemente no frontend o armazenamento deste cursor ao
    carregar mais registros.

Limitações do Cursor-Based Pagination

Ao contrário do Offset, o Cursor-Based Pagination não permite navegação direta para
qualquer página arbitrária, pois depende do último cursor recebido. Ele é ideal para
fluxos contínuos como scroll infinito, mas não para cenários onde ir para a página X é
fundamental.

Atenção

Cursor-Based depende de um campo ordenável confiável (ID incremental, data, número
serial). Em bancos onde o identificador é um UUID v4 (sem ordenação temporal), não é
possível usar essa abordagem corretamente – prefira UUID v7 ou campos com data/hora.

Desafios com IDs não ordenáveis e alternativas

Quando o campo de identificação não é sequencial (como UUID v4), o banco não consegue
definir a ordem natural dos registros para Cursor-Based Pagination. Isso impede ordenar
ou filtrar registros pela ordem de criação. Para casos assim, o recomendado é adotar um
campo de data ou migrar para UUID v7 (ordenável por tempo).

Atenção

Não tente forçar paginação cursor por UUID v4: as páginas se tornam imprevisíveis e
até inconsistentes para o usuário.

Comparando Offset-Based e Cursor-Based Pagination

Offset-Based Pagination

Paginação tradicional usando OFFSET e LIMIT para navegar por páginas exatas.

+ Prós

  • • Permite pular para qualquer página rapidamente
  • • Simples de implementar

− Contras

  • • Degrada progressivamente a performance com o aumento de registros
  • • Alto consumo de recursos em páginas avançadas

Cursor-Based Pagination

Utiliza um campo ordenável como referência, buscando sempre a partir do elemento mais recente processado.

+ Prós

  • • Performance estável, mesmo com milhões de registros
  • • Ideal para scroll infinito e APIs modernas

− Contras

  • • Impossibilita navegação por página exata
  • • Depende de campo ordenável confiável

Ferramentas e recursos para implementar e testar paginação

Resumo: Escolhendo a melhor estratégia de paginação

Para aplicações e painéis onde o volume de dados é pequeno e a navegação direta por
página é necessária, Offset-Based Pagination ainda é eficiente. Em APIs modernas, listas
longas e scroll infinito, Cursor-Based Pagination entrega performance muito superior e
estabilidade, sendo indispensável para grandes volumes de dados.

Erros comuns e como evitá-los

  1. Erro 1: Usar OFFSET em tabelas com milhões de linhas sem
    índices robustos.
  2. Erro 2: Implementar cursor em campos não ordenáveis ou não
    únicos.
  3. Erro 3: Não considerar plano de execução de queries em
    ambientes de produção.

Checklist de implementação de paginação eficiente

Checklist de Implementação

  • Identifique o volume de registros envolvidos na listagem por tabela
  • Avalie se a experiência exige navegação direta entre páginas ou scroll infinito
  • Selecione o método de paginação de acordo com o cenário: OFFSET ou Cursor
  • Garanta existência de índices nos campos usados para ordenação ou cursor
  • Teste performance de queries reais com Explain ou ferramentas similares
  • Evite cursors em campos UUID v4; use UUID v7, datas ou incrementais
  • Implemente e monitore consumo de recursos no banco e app

Perguntas frequentes

Offset vs cursor pagination?

Cursor escala melhor em feeds grandes. Offset é simples e quebra com inserts.

Quando offset ok?

Admin lists pequenas.

API pública?

Prefira cursor/keyset.

Com React Query?

Use pageParam/cursor consistente.

Continue explorando

Perguntas frequentes

Offset vs cursor pagination?

Cursor escala melhor em feeds grandes. Offset é simples e quebra com inserts.

Quando offset ok?

Admin lists pequenas.

API pública?

Prefira cursor/keyset.

Com React Query?

Use pageParam/cursor consistente.

O que é Offset-Based Pagination?

O modelo Offset-Based Pagination utiliza os comandos OFFSET e LIMIT nas queries para retornar apenas um subconjunto de registros, permitindo navegar entre "páginas" de dados com facilidade. Por exemplo, ao consultar a página 2 com 10 itens por página, você faz OFFSET 10 LIMIT 10, pulando os 10 primeiros e pegando os próximos 10 resultados.

Por que o OFFSET traz problemas de performance?

Quando se trabalha com tabelas que possuem milhões de registros, o banco precisa percorrer (e processar) todos os registros até o número do OFFSET antes de retornar o resultado solicitado. Isso faz com que consultas em páginas distantes da primeira aumentem exponencialmente em tempo de execução e uso de memória, tornando o processo cada vez mais lento e custoso.

Quando usar Offset-Based Pagination de forma segura

Offset-Based Pagination é suficiente e eficiente quando você trabalha com um volume pequeno ou moderado de dados (centenas a poucos milhares de registros), onde o overhead de ignorar múltiplos registros não afeta significativamente o desempenho. Também é útil quando a navegação direta entre páginas exatas é importante para o usuário.

Paginação com Scroll Infinito: o que muda?

Em interfaces modernas, cada vez mais comuns são as listas com carregamento contínuo (scroll infinito), como exemplos do Twitter e Instagram. Nesses casos, o usuário não seleciona páginas, mas carrega os itens seguintes conforme rola a tela. Aqui, a abordagem com OFFSET rapidamente se torna ineficiente.

Como funciona Cursor-Based Pagination

Em vez de pular um número fixo de registros, você envia o valor do último campo ordenável exibido (como o ID ou data) como cursor para a próxima consulta. Por exemplo, WHERE id > 400, LIMIT 20. Assim, só os registros após o último são trazidos, sem custo extra de leitura de dados.