TGStat
TGStat
Qidiruv uchun matnni kiriting
Ilg‘or kanal qidiruvi
  • flag Uzbek
    Sayt tili
    flag Russian flag English flag Uzbek
  • Saytga kirish
  • Katalog
    Kanal va guruhlar katalogi Hududiy to‘plamlar Tematik to‘plamlar Платные каналы Kanallar qidiruvi
    Kanal/guruh qo‘shish
  • Reytinglar
    Kanallar reytingi Guruhlar reytingi Postlar reytingi
    Brendlar va shaxslar reytingi
  • Analitika
  • Postlarda qidiruv
  • Telegram'ni kuzatish
  • Targ‘ibot
    Yandex Business orqali reklama TGStat Agency orqali kanallarda reklama TGStat.ru saytida reklama
Женя Янченко

9 Sep, 09:37

Telegram'da ochish Ulashish Shikoyat qilish

Пагинация при работе с БД

Хочу рассказать не только базовую теорию, но и про подводные камни и практические подходы к оптимизации.

➡️ OFFSET пагинация

Это самый распространенный вариант.
С фронтенда приходит запрос вида:

GET /orders?page=3&size=20

Если считаем, что страницы нумеруются с 1 (не с 0), то для page = 3 бэк превратит это примерно в такой запрос:

SELECT ...
FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 20
OFFSET 40;

Без ORDER BY порядок строк не гарантирован, а дополнительный уникальный id пригодится на случай одинакового created_at.


Что возвращает бэк:
{
"items": [...],
"page": 3,
"size": 20,
"totalElements": 247,
"totalPages": 13
}


У OFFSET пагинации много плюсов:

➕ просто реализовать, есть встроенная реализация в некоторых фреймворках

➕ легко реализовать переход к любой странице

Например, когда книгу то читаю, то слушаю, мне бывает надо сразу перейти на страницу 134.
Или помнила, что в адмике нужная запись на 78 странице 🤪

Но у такого подхода есть и минусы.

Ключевое слово OFFSET 40 говорит базе, что нужно пропустить первые 40 записей и начать отдавать, начиная с 41-й (для 3-й страницы). Однако база не может сразу прыгнуть на 41-ю строку. Она работает так:

➡️ найти начало упорядоченной выборки
➡️ пройти первые 40 записей
➡️ отбросить их
➡️ вернуть следующие 20 записей

Тут наблюдается лишняя работа с первыми 40 записями. Чем больше номер страницы, тем больше OFFSET и тем больше времени понадобится базе на ответ — это и есть основной минус.

Из-за большего OFFSET записи с последних страниц будут отдаваться дольше, чем с первых, но иногда возможен лайфхак с разворотом сортировки.

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

SELECT ...
FROM orders
ORDER BY created_at ASC, id ASC
LIMIT 20;

Оговорюсь, что такой запрос подходит для задачи "дай 20 самых ранних записей", но не является способом получить последнюю страницу классической пагинации, потому что возможно следующее несоответствие:

Всего 53 записи, размер страницы 20.
1 стр: 1-20 - 20 строк
2 стр: 21-40 - 20 строк
3 стр: 41-53 - 13 строк

ORDER BY created_at ASC LIMIT 20 вернет 20 самых старых строк вместо 13.


Проблема с OFFSET пагинацией может стать заметной, когда запрашиваются глубокие страницы: чем больше OFFSET, тем больше результатов базе приходится обработать и отбросить. Это может не проявляться на пользовательском UI с 10 страницами по 50 элементов, а вот если мы пишем публичный технический API, которым будут пользоваться соседние команды для получения каких-то больших списков, то там это может стать заметно:

SELECT ...
FROM payments
ORDER BY created_at DESC, id DESC
LIMIT 500
OFFSET 70000;
😱

Еще OFFSET пагинация может быть не очень удобна, когда список часто меняется.

Вообще это довольно редкий кейс, но давайте рассмотрим на всякий случай.

➡️ В БД лежат новости с id = 1 ... 100

➡️ Пользователь запросил 10 самых свежих новостей

➡️ Бэк отдал последние новости с id = 100, 99 ... 92, 91

➡️ Пока пользователь читал новости, модератор добавил две новых записи, они получили id = 101 и id = 102

➡️ Пользователь запросил следующую страницу более старых новостей

➡️ При выполнении OFFSET 10 БД отбросила записи с id = 102 ... 93 и отдала новости с id = 92, 91, 90 ...

➡️ Результат: пользователь дважды увидел новости с id = 92 и 91

Итого минусы:

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

Когда использовать OFFSET-пагинацию:

✅ пользователи обычно работают с первыми страницами списка, глубокие переходы редки (или количество строк в таблице небольшое, если очень грубо —несколько тысяч строк)

✅ список записей обычно не меняются, пока пользователь их смотрит

✅ на UI нужен блок с привычной пагинацией и переходом на конкретную страницу

2k 0 24 3 39
Katalog
Kanal va guruhlar katalogi Kanallar to‘plamlari Kanallar qidiruvi Kanal/guruh qo‘shish
Reytinglar
Telegram-kanallar reytingi Telegram-guruhlar reytingi Postlar reytingi Brendlar va shaxslar reytingi
API
Statistika API'si Postlar qidiruvi API'si API Callback
Kanallarimiz
@TGStat @TGStat_Chat @telepulse @TGStatAPI
O‘qish
Академия TGStat Telegram tadqiqoti 2019 Telegram tadqiqoti 2021 Telegram tadqiqoti 2023
Kontaktlar
Справочный центр Qo‘llab-quvvatlash Email Vakansiyalar
Har xil narsalar
Foydalanuvchi shartnomasi Maxfiylik siyosati Ommaviy oferta
Botlarimiz
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot