Аналитика включает в себя вычисление данных для поиска закономерностей. Начиная с простых вычислений, таких как сумма значений или ее среднее значение, и заканчивая статистикой, рассчитанной с помощью алгоритмов машинного обучения, аналитика часто имеет дело с большими объемами данных, которые необходимо обрабатывать как можно быстрее.
Мы видели в предыдущей части этой серии статей, как индексы помогают повысить скорость операций с базой данных. И, честно говоря, проблема в лабораторном приложении, показанном в этой статье, может быть решена простым добавлением индекса. Однако в реальных приложениях со многими таблицами, содержащими много столбцов, работа с индексами может оказаться затруднительной. В этой статье я исследую одну интересную технологию, которая помогает с аналитическими 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) ListfindTopAuthors(int bookCount);
Повторно запустите приложение и посмотрите, как теперь книги извлекаются менее чем за секунду!
Оригинал: “https://dev.to/alejandro_du/improving-backend-performance-part-33-fast-analytics-1a6h”