Dica Rápida: Paginando no MSSQL considerando escala

William Santos - Jul 24 '20 - - Dev Community

Olá!

Este post é uma breve continuação do Dica Rápida: Paginando no MSSQL com Offset e Fetch.

Antes de começar, gostaria de agradecer aos colegas Rafael Ponte e Renato Todorov que fizeram considerações sobre alto volume de dados na Dica Rápida anterior, dando origem a esta continuação! Obrigado, pessoal!

Vamos lá?

Muito embora, para cenários mais simples, com baixo volume de dados, o uso de Offset e Fetch seja suficiente, quando precisamos trabalhar com grandes volumes, a história muda.

Explico.

No último post disse que a instrução Offset vai pular a quantidade de linhas informada. Certo? Pois é! Mas para que o banco saiba quantas e quais linhas pular, ele precisa percorrê-las primeiro. Ou seja, o banco vai percorrer todas as linhas que respeitem o critério BirthDate e, em seguida, vai usar as instruções Offset e Fetch para decidir quais linhas retornar.

E é aí que mora o problema porque, quanto mais linhas sua tabela tiver, e quanto maior for o Offset informado, maior será o número de linhas que deverá ser percorrido antes de retornar a quantidade solicitada pelo uso do Fetch! E este é um baita prejuízo para a performance se for preciso paginar milhares de registros.

Mas, então, como resolver isso? Por incrível que pareça, é fácil! A solução se chama keyset pagination (ou cursor pagination)!

Em vez de informarmos ao banco em qual página estamos, informaremos o último Id que lemos, retornaremos apenas os registros de Id superior, e assim eliminamos o esforço do Offset.

O código anterior seria convertido para o seguinte:

SELECT TOP (@PageSize)
    Id,
    FirstName, 
    LastName
FROM 
    Customer
WHERE 
    Id > @LastId -- Ou Id < @LastId se a intenção for retroceder uma página
AND
    BirthDate >= '2000-01-01'
ORDER BY
    Id
Enter fullscreen mode Exit fullscreen mode

Aparentemente não mudou muita coisa. Não é? Mas, do ponto de vista do banco, essa simples mudança representa um enorme alívio porque, desta forma, não precisamos mais instruir o banco a subdividir a consulta com todos os resultados que atendam ao critério BirthDate informado, pois a informação do TOP no SELECT, e do último Id conhecido na cláusua WHERE, são o suficiente para instruir o banco sobre a partir de qual linha ele deve começar, e até quantas linhas ele precisa percorrer.

Nota: A coluna Id pode combinada com, ou substituída por, qualquer coluna indexada.

Legal. Né?

Gostou? Me deixe saber pelos indicadores. Dúvidas? Me envie pelos comentários que responderei assim que puder.

Até a próxima!

Referências:

Please Don't Use OFFSET and LIMIT For Your Pagination

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .