Fala galera!
Nesse post, eu gostaria de demonstrar a vocês como criar uma paginação de dados no SQL Server, de modo que apenas uma quantidade limitada de registros sejam retornados pelas consultas, fazendo com que menos dados sejam processados na saída e as consultas tenham um tempo de resposta menor. Cenário esse, que é bastante comum em aplicações, que costumam paginar os dados na tela, tanto para evitar o excesso de informação quanto para diminuir o tempo necessário para carregar as informações.
Com o surgimento do ROW_NUMBER() no SQL Server 2005, muitas pessoas passaram a utilizar essa função para criar paginação de dados, funcionando desta forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
DECLARE @Pagina INT = 5, @ItensPorPagina INT = 10 SELECT * FROM ( SELECT [name], ROW_NUMBER() OVER(ORDER BY [name]) AS Ranking FROM sys.objects ) A WHERE A.Ranking >= ((@Pagina - 1) * @ItensPorPagina) + 1 AND A.Ranking < (@Pagina * @ItensPorPagina) + 1 |
Entretanto, a partir do SQL Server 2012 temos a funcionalidade de paginação nativa no próprio SQL Server e que muita gente acaba não utilizando por desconhecimento. Estamos falando do recurso OFFSET e FETCH, que funcionam juntos para permitir que possamos paginar os nossos resultados antes de exibir e enviá-los para as aplicações e clientes.
Vejam com o seu uso é simples:
1 2 3 4 5 |
SELECT [name] FROM sys.objects ORDER BY [name] OFFSET 40 ROWS -- Linha de início: Vai começar a retornar a partir da linha 40 FETCH NEXT 10 ROWS ONLY -- Quantidade de linhas para retornar: Vai retornar as próximas 10 linhas |
E se a gente quiser algo parametrizável, assim como o exemplo anterior, podemos utilizar a mesma estrutura do exemplo anterior:
1 2 3 4 5 6 7 8 9 |
DECLARE @Pagina INT = 5, @ItensPorPagina INT = 10 SELECT [name] FROM sys.objects ORDER BY [name] OFFSET (@Pagina - 1) * @ItensPorPagina ROWS FETCH NEXT @ItensPorPagina ROWS ONLY |
Vamos agora, analisar o desempenho das duas consultas para verificar se além da facilidade, temos alguma vantagem em relação à performance:
Analisando o plano de execução, a solução com OFFSET e FETCH parece utilizar menos operadores e apresentar um plano mais simples. Vamos agora os números na prática:
Vou alterar as consultas e tentar ordenar por uma coluna VARCHAR, não indexada, para verificar se há alguma mudança no desempenho das 2 soluções:
Bom, analisando os resultados dos testes que realizei, ficou claro que, embora essa solução seja mais prática de implementar, ela fica um pouco atrás no quesito performance.
Acredito que em um cenário real do dia a dia, essa diferença de performance acabe não sendo tão relevante (dependendo do uso da aplicação), mas fica a dica sobre a relação de custo x benefício entre praticidade e performance ao utilizar paginação no SQL Server com ROW_NUMBER() ou OFFSET + FETCH. Caso você queira se aprofundar na análise de performance do OFFSET + FETCH, recomendo a leitura do do artigo Pagination with OFFSET / FETCH : A better way, do Aaron Bertrand.
Espero que tenham gostado desse post, onde apresentei como criar paginação de dados no SQL Server utilizando ROW_NUMBER() ou OFFSET + FETCH NEXT n ROWS ONLY.
Um abraço e até a próxima!
muito boa a comparação!