Пагинация с офсетом, курсорная и keyset-пагинация, бесконечный скролл
Пагинация — это процесс разделения большого набора данных на более мелкие, управляемые части (страницы), чтобы улучшить производительность и пользовательский опыт.
| Метод | Производительность | Стабильность при изменениях | Случайный доступ | Бесконечный скролл | Пример SQL |
|---|---|---|---|---|---|
| Offset-based | O(N) при больших offset | Низкая (дубликаты/пропуски) | Да | Нет | SELECT * FROM posts LIMIT 10 OFFSET 100 |
| Cursor-based (Keyset) | O(1) с индексом | Высокая | Нет (только вперед) | Да | SELECT * FROM posts WHERE id > 123 ORDER BY id ASC LIMIT 10 |
| Page-based | O(1) | Средняя | Да | Нет | SELECT * FROM posts WHERE page = 5 |
| Time-based | O(1) | Высокая | Ограниченный | Да | SELECT * FROM logs WHERE created_at < '2024-01-01' ORDER BY created_at DESC LIMIT 10 |
REST API с cursor-based пагинацией:
GET /posts?cursor=123&limit=10Ответ:
{
"data": [
{ "id": 124, "title": "Post 124" },
{ "id": 125, "title": "Post 125" }
],
"pagination": {
"next_cursor": "125",
"has_more": true,
"total_count": 1000
}
}Реализация на сервере (Node.js):
app.get('/posts', (req, res) => {
const cursor = req.query.cursor || 0;
const limit = parseInt(req.query.limit) || 10;
const posts = db.posts
.find({ id: { $gt: cursor } })
.sort({ id: 1 })
.limit(limit);
const nextCursor = posts.length > 0 ? posts[posts.length - 1].id : null;
res.json({
data: posts,
pagination: {
next_cursor: nextCursor,
has_more: posts.length === limit,
total_count: db.posts.count()
}
});
});| Критерий | Рекомендуемый метод | Обоснование |
|---|---|---|
| Большие объемы данных (>100K записей) | Cursor-based | O(1) производительность, стабильные результаты |
| Необходимость случайного доступа к страницам | Offset-based или Page-based | Только они поддерживают прямой переход по номеру страницы |
| Бесконечный скролл UI | Cursor-based | Естественная поддержка последовательной загрузки |
| Временные данные (логи, события) | Time-based | Логично по времени, а не по ID |
| Простота реализации для MVP | Offset-based | Минимальная сложность, быстрая разработка |
Q: В чём разница между пагинацией с офсетом и курсорной пагинацией?
A: Офсет: LIMIT 10 OFFSET 100 — медленно на больших офсетах; Курсорная: WHERE id > last_id LIMIT 10 — быстро, но только прямая навигация.
Q: Какой тип пагинации лучше подходит для бесконечного скролла? A: Cursor-based — эффективная загрузка следующей порции по последнему ID. Это идеально подходит для бесконечного скролла, так как позволяет эффективно загружать следующую порцию данных, зная только последний ID или временную метку предыдущей порции.
Q: Какая основная проблема offset-based пагинации при работе с большими данными?
A: O(N) сложность сканирования — СУБД пропускает записи линейно. При запросе OFFSET 1000000 СУБД должна пропустить первые миллион записей, что приводит к значительному замедлению.
Q: Что такое 'keyset pagination'? A: Keyset pagination — это другое название для cursor-based пагинации, где клиент передает значение ключа (обычно ID или временную метка) последней записи на предыдущей странице, и сервер выбирает записи, которые идут после него.
Выбор метода зависит от требований к производительности, объема данных и необходимой функциональности (например, возможность перехода на конкретную страницу).
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.