Отвечает эксперт сообщества Spring АйО – Михаил Поливаха.
–––
Есть один довольно маленький фикс, который Вы можете сделать в Spring Data, чтобы улучшить перформанс Ваших приложений, иногда заметно.
Не все знают, но пагинация бывает разная. Часто она нам нужна для того, чтобы не грузить все данные в память процесса. Ситуация схожая, если данные нужны front-end'у, и мы не хотим гонять огромные массивы данных по сети, front-end же в свою очередь будет рендерить их довольно долго, да и на практике так никто не делает. Чтобы адресовать подобные проблемы, мы используем пагинацию.
Возьмем Spring Data JPA (на самом деле неважно, какой именно модуль Spring Data вы тут возьмете, концепция везде едина). Предположим, что у нас есть сущность:
@Entity
public class SimpleEntity {
@Id
@Column(name = "id", nullable = false)
private Long id;
private String name;
private long createdAt;
// getters, setters, toString
}
и 2 метода в репозитории:
@Query("SELECT p FROM SimpleEntity p WHERE p.name LIKE :namePattern")
Slice<SimpleEntity> findCustomSlice(Pageable pageable, @Param("namePattern") String namePattern);
@Query("SELECT p FROM SimpleEntity p WHERE p.name LIKE :namePattern")
Page<SimpleEntity> findCustomPage(Pageable pageable, @Param("namePattern") String namePattern);
Они отличаются лишь типом возвращаемого значения. В первом случае -
Slice, во втором - Page. Если вызвать первый метод, возвращающий Slice, то выполнится вот такой запрос (в общем случае):
select
se1_0.id,
se1_0.created_at,
se1_0.name
from
simple_entity se1_0
where
se1_0.name like ? escape ''
order by
se1_0.id
offset
? rows
fetch
first ? rows only
Но чаще всего люди используют
Page. В этом случае Spring Data пошлёт запрос описанный выше и, вдобавок, ещё один запрос:
select
count(se1_0.id)
from
simple_entity se1_0
where
se1_0.name like ? escape ''
–
Slice в Spring Data, как абстракция, представляет собой некоторую часть данных из общего датасета, некоторую страничку. Но эта страничка не знает о том, сколько всего страниц существует. Она знает свой порядковый номер, но она не знает, сколько страниц ещё впереди.–
Page расширяет понятие Slice, добавляя при этом страничке понимание того, а сколько страниц впереди неё, и сколько всего страниц в выборке. Для того, чтобы это понять, и нужен второй count() запрос.Вывод
Если Вам не нужно знать общее количество страниц в выборке, то используйте
Slice - на каждый запрос за каждой страницей вы сэкономите один count запрос. Если вам нужно знать общее количество страниц в выборке (оно, скорее всего, не меняется, пока пользователь листает страницы, хотя имейте это в виду), то вы можете один раз отправить на front-end результат выполнения запроса с
count() и дальше использовать Slice. Реализовать это можно по-разному.❗️ Подробнее, как ещё можно оптимизировать постраничную навигацию, вы можете узнать в докладе экспертов сообщества (Ильи и Фёдора Сазоновых) на Jpoint 2023.