Рубрики
Без рубрики

Повышение производительности серверной Части, Часть 3/3: Быстрая аналитика

Аналитика включает в себя вычисление данных для поиска закономерностей. Из простых вычислений – таких, как… С тегами java, sql, database, mariadb.

Аналитика включает в себя вычисление данных для поиска закономерностей. Начиная с простых вычислений, таких как сумма значений или ее среднее значение, и заканчивая статистикой, рассчитанной с помощью алгоритмов машинного обучения, аналитика часто имеет дело с большими объемами данных, которые необходимо обрабатывать как можно быстрее.

Мы видели в предыдущей части этой серии статей, как индексы помогают повысить скорость операций с базой данных. И, честно говоря, проблема в лабораторном приложении, показанном в этой статье, может быть решена простым добавлением индекса. Однако в реальных приложениях со многими таблицами, содержащими много столбцов, работа с индексами может оказаться затруднительной. В этой статье я исследую одну интересную технологию, которая помогает с аналитическими SQL-запросами: Хранилище столбцов с использованием Пружинной загрузки и Поток Ваадина

Прочитайте часть 1 этой серии если вы хотите узнать как работает пример приложения, которое мы будем использовать здесь, и часть 2 если вы хотите увидеть возможности индексов базы данных в действии. Вы можете найти код на GitHub . Кроме того, и если вы предпочитаете, я записал видеоверсию этой статьи:

Требование

Допустим, мы разрабатываем веб-страницу (или представление, в терминологии Vaadin) для отображения аналитических данных; отчет, если хотите. В частности, мы хотим начать с показа лучших авторов (из базы данных book_demo ) в соответствии с количеством опубликованных ими книг. Предположим, что лучший автор – это автор с более чем 12 опубликованными книгами. Мы должны показать сетку с именем лучшего автора и количеством опубликованных книг.

Добавление собственного запроса в репозиторий

Давайте начнем с добавления собственного запроса. Мы могли бы использовать запрос JPQL, но чтобы легче понять суть этой статьи, собственный запрос упростит ситуацию.   Кроме того, мы увидим, как использовать собственные запросы с Spring Data .

При использовании собственных запросов с данными Spring нам не нужно использовать классы сущностей JPA. Вместо этого мы можем определить настраиваемый view результата запроса в виде интерфейса Java с одним получателем для каждого столбца в результате запроса. Вот запрос, который нам нужен в классе репозитория:

@Repository
public interface BookRepository extends JpaRepository {

    interface TopAuthor{
        String getAuthor();
        int getBookCount();
    }

    ...

    @Query(value = "select author, count(id) as bookCount from book group by author having count(id) > ?1", nativeQuery = true)
    List findTopAuthors(int bookCount);

}

Обратите внимание, что мы использовали собственный запрос в аннотации @Query . Spring Data создаст объекты типа Top Author для построения результата List .

Нам также необходимо обновить класс сервиса, чтобы пользовательский интерфейс мог извлекать лучших авторов:

@Service
public class BookService {

    private final BookRepository repository;

    ...

    public List findTopAuthors(int bookCount) {
        return repository.findTopAuthors(bookCount);
    }

}

Добавление представления (поток Vaadin)

Нам нужно добавить новое представление потока Vaadin, или веб-страницу, или маршрут. Все они почти синонимы (за исключением того, что технически это не веб-страница, но давайте пока не будем об этом беспокоиться). Вот реализация:

@Route("report")
public class ReportView extends VerticalLayout {

    public ReportView(BookService service) {
        var grid = new Grid<>(BookRepository.TopAuthor.class);
        grid.setSizeFull();
        grid.setItems(service.findTopAuthors(12));

        add(grid);
        setSizeFull();
    }
}

Этот короткий класс создает в нем вертикальный макет (с сеткой) и предоставляет его по адресу http://localhost:8080/report . Компонент Grid заполняется лучшими авторами, возвращаемыми классом service.

Тестирование медленного поведения

Запустите приложение, запустив метод main в классе Application , и посмотрите результат в браузере. В зависимости от количества книг, имеющихся в вашей базе данных, представление будет отображаться быстро или значительно медленно! В моем случае я добавил в базу данных миллион книг (я написал article это показывает вам, как создать много книг для вашей базы данных). С одним миллионом книг просмотр занимает несколько секунд, чтобы появиться в браузере, как вы можете видеть в видео .

Использование ColumnStore

Как я уже упоминал во введении, эту проблему можно решить, добавив индекс в столбец author . Это работает в этом чрезмерно упрощенном примере, но в реальном проекте у вас легко могут быть сотни таблиц с десятками столбцов в каждой. Работа с индексами становится, мягко говоря, довольно сложной. Mariadb ColumnStore позволяет нам, помимо прочего, использовать преимущества индексов без необходимости настраивать индексы вручную.

Давайте создадим новую таблицу, используя механизм хранения столбцов:

CREATE TABLE book_analytics
(
    id           int(11) NOT NULL,
    author       varchar(255) DEFAULT NULL,
    pages        int(11)      DEFAULT NULL,
    publish_date date         DEFAULT NULL,
    title        varchar(255) DEFAULT NULL
) engine=ColumnStore;

Я опустил столбец image_data из исходной таблицы book , поскольку нет смысла размещать его в таблице, используемой в аналитических целях. Обратите внимание, что мы не можем добавлять индексы к таблицам, использующим механизм хранения столбцов. Нам и не нужно этого делать. Это одно из преимуществ.

Мы должны заполнить эту новую таблицу из исходной. Поскольку MariaDB использует подключаемые движки, их можно смешивать в одном экземпляре базы данных и в операторах SQL, поэтому мы можем просто копировать данные из одной таблицы в другую с помощью SQL, даже если они используют разные движки:

insert into book_analytics(id, author, pages, publish_date, title)
    select id, author, pages, publish_date, title from book;

Тестирование улучшения

Перед тестированием улучшения нам нужно использовать таблицу book_analytics в запросе, который мы добавили в репозиторий:

@Query(value = "select author, count(id) as bookCount from book_analytics group by author having count(id) > ?1", nativeQuery = true)
    List findTopAuthors(int bookCount);

Повторно запустите приложение и посмотрите, как теперь книги извлекаются менее чем за секунду!

Оригинал: “https://dev.to/alejandro_du/improving-backend-performance-part-33-fast-analytics-1a6h”