MariaDB
 sql >> Base de Dados >  >> RDS >> MariaDB

Melhorando o desempenho do back-end Parte 2/3:usando índices de banco de dados


Os índices de banco de dados são uma preocupação dos desenvolvedores. Eles têm o potencial de melhorar o desempenho dos recursos de pesquisa e filtro que usam uma consulta SQL no back-end. Na segunda parte desta série de artigos, mostrarei o impacto que um índice de banco de dados tem na aceleração de filtros usando uma aplicação web Java desenvolvida com Spring Boot e Vaadin.

Leia a parte 1 desta série se quiser saber como funciona o aplicativo de exemplo que usaremos aqui. Você pode encontrar o código no GitHub. Além disso, e se preferir, gravei uma versão em vídeo deste artigo:

O requisito


Temos uma página web com uma grade que mostra uma lista de livros de um banco de dados MariaDB:



Queremos adicionar um filtro para permitir que os usuários desta página vejam quais livros foram publicados em uma determinada data.

Implementando a consulta e o serviço do repositório


Precisamos fazer algumas alterações no back-end para oferecer suporte à filtragem de dados pela data de publicação. Na classe do repositório, podemos adicionar o seguinte método:

@Repository
public interface BookRepository extends JpaRepository<Book, Integer> {

    Page<Book> findByPublishDate(LocalDate publishDate, Pageable pageable);

}

Isso usa carregamento lento, como vimos na parte 1 desta série de artigos. Não precisamos implementar esse método — o Spring Data o criará para nós em tempo de execução.

Também temos que adicionar um novo método à classe de serviço (que é a classe que a interface do usuário usa para executar a lógica de negócios). Veja como:

@Service
public class BookService {

    private final BookRepository repository;

    ...

    public Stream<Book> findAll(LocalDate publishDate, int page, int pageSize) {
        return repository.findByPublishDate(publishDate, PageRequest.of(page, pageSize)).stream();
    }

}

Adicionando um filtro à página da Web


Com o backend compatível com a filtragem de livros por data de publicação, podemos adicionar um seletor de datas à implementação da página da Web (ou visualização):

@Route("")
public class BooksView extends VerticalLayout {

    public BooksView(BookService service) {

        ...

        var filter = new DatePicker("Filter by publish date");
        filter.addValueChangeListener(event ->
                grid.setItems(query ->
                        service.findAll(filter.getValue(), query.getPage(), query.getPageSize())
                )
        );

        add(filter, grid);
        setSizeFull();
    }

    ...
}

Este código apenas cria um novo DatePicker objeto que escuta as mudanças em seu valor (através de um ouvinte de mudança de valor). Quando o valor muda usamos a classe de serviço para obter os livros publicados na data selecionada pelo usuário. Os livros correspondentes são então definidos como itens da Grid .

Testando a consulta lenta


Implementamos o filtro; no entanto, é extremamente lento se você tiver, por exemplo, 200 mil linhas na tabela. Tente! Escrevi um artigo que explica como gerar dados de demonstração realistas para aplicativos Java. Com esse número de linhas, o aplicativo levou vários segundos para mostrar os dados na página da web em minha máquina (MacBook Pro 2,3 GHz Quad-Core Intel Core i5). Isso arruína completamente a experiência do usuário.

Analisando consultas com "Explicar consulta"


Se você ativou o log de consultas, você pode encontrar a consulta gerada pelo Hibernate no log do servidor. Copie-o, substitua os pontos de interrogação por valores reais e execute-o em um cliente de banco de dados SQL. Na verdade, posso poupar-lhe algum tempo. Aqui está uma versão simplificada da consulta:

SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';

MariaDB inclui o EXPLAIN instrução que nos fornece informações úteis sobre como o mecanismo estima que executará a consulta. Para usá-lo, basta adicionar EXPLAIN antes da consulta:

EXPLAIN SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';

Aqui está o resultado:

A documentação tem tudo o que você precisa saber sobre ela, mas o importante é o valor no tipo coluna:TODOS . Esse valor nos diz que o mecanismo estima que terá que buscar ou ler todas as linhas da tabela. Não é uma coisa boa.

Criando um índice


Felizmente, podemos corrigir isso facilmente criando um índice na coluna que estamos usando para filtrar os dados:publish_date . Veja como:

CREATE INDEX book\_publish\_date_index ON book(publish_date);

Um índice de banco de dados é uma estrutura de dados criada pelo mecanismo, geralmente uma b-tree (b para equilibrado ), e isso acelera o processo de encontrar uma determinada linha em uma tabela, ou seja, procurar uma linha dado o valor na coluna na qual o índice é construído. O processo é mais rápido graças à natureza das b-trees - elas mantêm os dados ordenados reduzindo a complexidade do tempo de O(N) para O(log(N)) e até O(log(1)) em alguns casos.

Testando a melhoria


Com o índice construído, podemos executar a instrução EXPLAIN novamente e ver que a coluna type mostra o valor ref em vez de TODOS :

A referência value significa que o mecanismo usará o índice quando executarmos a consulta. É importante que você verifique isso ao adicionar índices às suas consultas mais complexas. Sempre use o EXPLAIN para verificar novamente se você está ganhando desempenho ao introduzir um índice.

Se você experimentar o aplicativo da web no navegador e selecionar outra data no seletor de datas (não é necessário reiniciar o servidor), verá uma enorme diferença! Por exemplo, os dados são recuperados em menos de um segundo na minha máquina, em contraste com vários segundos antes de criarmos o índice!