Executando verificação de segurança...
2

Melhorando a Performance de suas buscas com paginação

Este post acompanha o video que gravei recentemente sobre o assunto: https://www.youtube.com/watch?v=-AgDQEQhOfw


Quem nunca se deparou com uma aplicação que ficou lenta ou até mesmo travou durante uma busca?

Pois é, uma das razões para esse problema pode ser a falta de implementação de paginação.

Vamos demonstrar como a paginação pode nos ajudar a obter máximo desempenho.

Entendendo o Funcionamento

Imaginem uma situação em que uma busca retorna uma grande quantidade de resultados, como centenas, milhares ou até milhões de registros. Processar todos esses registros de uma vez pode sobrecarregar a aplicação, tornando-a lenta ou até mesmo causando crashes e bugs.

Uma solução para esse problema é quebrar os resultados da busca em partes, ou seja, em páginas.

Por exemplo, digamos que temos um banco de dados com a tabela item a seguir:

create table item (
    id integer not null,
    nome varchar(255)
)

Se tivermos cinco itens, podemos organizá-los em duas páginas, com três elementos na primeira e dois na segunda. Neste exemplo, estamos trabalhando com apenas cinco items, mas o mesmo conceito é aplicado quando temos muito mais registros em nosso banco de dados, poderiamos ter 10.000 items na tabela com 100 items em cada pagina . Isso torna o processamento mais eficiente e evita sobrecargas.

            +--------+
pagina_0    | item_0 |
            | item_1 |
            | item_2 |
            +--------+
    
            +--------+
pagina_1    | item_3 |
            | item_4 |
            +--------+

Java JPA Paginação

Para ilustrar, consideraremos o nosso exemplo com cinco itens. Criaremos uma classe de teste que vai salvar cinco itens no repositório.

// Poderia ser um for loop, mas estou usando o IntStream pelo 'cool factor'
IntStream.rangeClosed(0, 4).forEach(i -> {
    var item = new Item();
    item.setNome("item_" + i);
    itemRepository.save(item);
});
assertEquals(5, itemRepository.count());

A implementação da paginação propriamente dita começa com a utilização do método findAll do repositório, que recebe um objeto Pageable como argumento.
Para isso, criamos um PageRequest com um tamanho de página de três elementos.
Isso representa a primeira página, que capturamos em uma variável chamada pagina_0.
Verificamos se a pagina_0 contém apenas três elementos e se os elementos são mesmo os itens item_0, item_1, item_2, garantindo assim o sucesso da busca inicial.

var pagina_0 = itemRepository.findAll(PageRequest.ofSize(3));
assertEquals(3, pagina_0.getNumberOfElements());
assertEquals("item_0", pagina_0.getContent().get(0).getNome());
assertEquals("item_1", pagina_0.getContent().get(1).getNome());
assertEquals("item_2", pagina_0.getContent().get(2).getNome());

Acessando Páginas Subsequentes

Quando precisamos acessar as páginas seguintes, utilizamos o método findAll novamente, desta vez especificando o número da página desejada.
Neste caso, podemos construir a página utilizando o método PageRequest.of(1, 3) ou pagina_0.nextPageable().
Verificamos se a pagina_1 contém apenas três elementos e se os elementos são mesmo os itens item_3, item_4.

var pagina_1 = itemRepository.findAll(pagina_0.nextPageable());
assertEquals(2, pagina_1.getNumberOfElements());
assertEquals("item_3", pagina_1.getContent().get(0).getNome());
assertEquals("item_4", pagina_1.getContent().get(1).getNome());

SQL Gerado

O JPA gera dois SQL quando faz a paginação

select
    count(*) 
from
    item i1_0



select
    i1_0.id,
    i1_0.descricao,
    i1_0.nome,
    i1_0.qr_code_id 
from
    item i1_0 offset ? rows fetch first ? rows only

Considerações Finais

Vale lembrar que é importante ordenar os resultados quando utilizando paginação, mas este é um assunto que quero explorar em um post futuro.

Também quero mencionar que este é apenas um método de paginação, é um método genérico e fácil de implementar, existem outros métodos mais performáticos que também quero discutir em posts futuros.

Se tiver algum feedback, basta deixar nos comentários.

Carregando publicação patrocinada...