sql >> Base de Datos >  >> RDS >> MariaDB

Mejorar el rendimiento de back-end Parte 2/3:Uso de índices de bases de datos

Los índices de la base de datos son una preocupación de los desarrolladores. Tienen el potencial de mejorar el rendimiento de las funciones de búsqueda y filtrado que utilizan una consulta SQL en el backend. En la segunda parte de esta serie de artículos, mostraré el impacto que tiene un índice de base de datos en la aceleración de los filtros utilizando una aplicación web Java desarrollada con Spring Boot y Vaadin.

Lea la parte 1 de esta serie si desea saber cómo funciona la aplicación de ejemplo que usaremos aquí. Puedes encontrar el código en GitHub. Además, y si lo prefieres, grabé una versión en video de este artículo:

El requisito

Tenemos una página web con una cuadrícula que muestra una lista de libros de una base de datos MariaDB:

Queremos agregar un filtro para permitir que los usuarios de esta página vean qué libros se publicaron en una fecha determinada.

Implementación del servicio y la consulta del repositorio

Tenemos que hacer algunos cambios en el backend para admitir el filtrado de datos por fecha de publicación. En la clase de repositorio, podemos agregar el siguiente método:

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

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

}

Esto usa carga diferida como vimos en la parte 1 de esta serie de artículos. No tenemos que implementar este método:Spring Data lo creará para nosotros en tiempo de ejecución.

También tenemos que agregar un nuevo método a la clase de servicio (que es la clase que usa la interfaz de usuario para ejecutar la lógica empresarial). Así es cómo:

@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();
    }

}

Adición de un filtro a la página web

Con el backend que admite el filtrado de libros por fecha de publicación, podemos agregar un selector de fecha a la implementación de la página web (o vista):

@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 simplemente crea un nuevo DatePicker objeto que escucha los cambios en su valor (a través de un detector de cambio de valor). Cuando el valor cambia, usamos la clase de servicio para publicar los libros en la fecha seleccionada por el usuario. Los libros coincidentes se configuran como elementos de la Grid .

Prueba de la consulta lenta

Hemos implementado el filtro; sin embargo, es extremadamente lento si tiene, por ejemplo, 200 mil filas en la tabla. ¡Intentalo! Escribí un artículo que explica cómo generar datos de demostración realistas para aplicaciones Java. Con esta cantidad de filas, la aplicación tardó varios segundos en mostrar los datos en la página web de mi máquina (MacBook Pro 2,3 GHz Quad-Core Intel Core i5). Esto arruina por completo la experiencia del usuario.

Análisis de consultas con "Explicar consulta"

Si habilitó el registro de consultas, puede encontrar la consulta generada por Hibernate en el registro del servidor. Cópielo, reemplace los signos de interrogación con valores reales y ejecútelo en un cliente de base de datos SQL. De hecho, puedo ahorrarte algo de tiempo. Aquí hay una versión simplificada de la consulta:

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

MariaDB incluye el EXPLAIN declaración que nos da información útil sobre cómo el motor estima que se va a ejecutar la consulta. Para usarlo, simplemente agregue EXPLAIN antes de la consulta:

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

Aquí está el resultado:

La documentación tiene todo lo que necesita saber al respecto, pero lo importante es el valor en el tipo columna:TODOS . Este valor nos dice que el motor estima que tendrá que buscar o leer todas las filas de la tabla. No es algo bueno.

Creación de un índice

Afortunadamente, podemos arreglar esto fácilmente creando un índice en la columna que estamos usando para filtrar los datos:publish_date . Así es cómo:

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

Un índice de base de datos es una estructura de datos creada por el motor, generalmente un árbol b (b para equilibrado ), y eso agiliza el proceso de encontrar una determinada fila en una tabla, es decir, buscar una fila dado el valor en la columna sobre la que se construye el índice. El proceso es más rápido gracias a la naturaleza de los árboles b:mantienen los datos ordenados, lo que reduce la complejidad temporal de O(N) a O(log(N)) e incluso a O(log(1)) en algunos casos.

Probando la Mejora

Con el índice creado, podemos ejecutar la declaración EXPLAIN nuevamente y ver que la columna de tipo muestra el valor ref en lugar de TODOS :

El ref value significa que el motor usará el índice cuando ejecutemos la consulta. Es importante que verifique esto cuando agregue índices a sus consultas más complejas. Utilice siempre el EXPLAIN declaración para verificar dos veces que está ganando en rendimiento cuando introduce un índice.

Si prueba la aplicación web en el navegador y selecciona otra fecha en el selector de fechas (no es necesario reiniciar el servidor), verá una gran diferencia. Por ejemplo, los datos se recuperan en menos de un segundo en mi máquina en contraste con varios segundos antes de que creáramos el índice.