Как реализуешь пагинацию на стороне базы данных

Ответ

Для пагинации на стороне БД используют LIMIT и OFFSET в SQL-запросах. Например:

SELECT * FROM products 
ORDER BY id 
LIMIT 10 OFFSET 20; -- пропускаем 20 записей, берем 10

Но OFFSET неэффективен на больших данных - чем дальше, тем медленнее. Альтернатива - ключевой метод:

SELECT * FROM products 
WHERE id > 50 -- последний полученный ID
ORDER BY id 
LIMIT 10;

На фронте храним последний загруженный ID или другую уникальную метку. Это быстрее, так как БД использует индексы.

Для реализации в API обычно передают параметры:

  • limit - количество элементов
  • after или before - курсор для пагинации

Пример запроса:
GET /api/products?limit=10&after=50

Ответ 18+ 🔞

А, ну ты глянь, какие у нас тут проблемы с пагинацией! Сидят, блядь, разработчики, думают: "О, да я щас как накручу OFFSET 1000000, и всё будет летать!" А потом, сука, через месяц приложение еле ползает, и все удивляются — пиздец, откуда тормоза?

Так вот, слушай сюда, пока не поздно. Есть два пути, и один из них — дорога в ад.

Первый путь, для ленивых и наивных (он же "пиздец как тормозит"): Ты просто пишешь в запросе LIMIT и OFFSET. Типа, "дай мне 10 штук, начиная с 20-й". Выглядит просто, да?

SELECT * FROM products 
ORDER BY id 
LIMIT 10 OFFSET 20; -- пропускаем 20 записей, берем 10

И всё вроде бы работает, пока у тебя там 100 товаров. Но представь, что товаров — овердохуища. И кто-то решил посмотреть на 10000-ю страницу. Что делает БД? Она, сука, должна пройтись по всем этим 10000 10 записей, чтобы их пропустить*, и только потом взять свои 10. Это как искать иголку в стоге сена, предварительно пересчитав всё сено в стоге. Эффективность — ноль ебать. Запрос начинает тормозить хуже старого деда на костылях.

Второй путь, для умных и красивых (он же "ключевой метод" или "курсорная пагинация"): Тут мы не тупо пропускаем, а говорим БД: "Эй, дай мне 10 записей, но только тех, у которых id больше, чем последний, который я уже видел!". Блядь, и это гениально просто.

SELECT * FROM products 
WHERE id > 50 -- последний полученный ID
ORDER BY id 
LIMIT 10;

Почему это быстрее? Потому что у id, скорее всего, есть индекс! База данных не шарится по всей таблице, а сразу прыгает в нужное место по индексу и берёт следующие записи. Скорость — просто ёперный театр!

А как это на практике, в рот меня чих-пых? На фронте ты не считаешь страницы, а хранишь последний загруженный id (или другую уникальную метку, по которой сортируешь). Это твой курсор.

В API делаешь красивые параметры, а не page=100500:

  • limit — сколько элементов (всё как у людей).
  • after — курсор, после которого нужно искать (например, последний известный id).
  • before — можно и до курсора, если надо назад.

Пример запроса будет выглядеть солидно и не вызывать инфаркт у базы данных: GET /api/products?limit=10&after=50

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