Paginação Offset vs Cursor: Performance e Melhores Práticas no SQL
Descubra as diferenças e impactos reais das estratégias Offset-based e Cursor-based Pagination para bases de dados grandes. Aprenda como escolher a abordagem ideal em cada cenário e melhore a performance das suas queries.
Por que isso é importante
Uma implementação inadequada de paginação pode tornar grandes sistemas lentos, consumir recursos além do necessário e afetar negativamente a experiência do usuário. Escolher entre Offset-Based Pagination e Cursor-Based Pagination impacta diretamente performance, escalabilidade e custos de bancos de dados em aplicações modernas.
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.
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.
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
PostgreSQL Explain Analyze
Analisa planos de execução de queries e ajuda a identificar gargalos de OFFSET.
Saiba mais →SQLite Database Browser
Ferramenta grátis para explorar pequenas bases e simular diferentes métodos de paginação.
Saiba mais →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.