Русский
Русский
English
Статистика
Реклама

Перевод Дизайн пагинации страниц в API

Для API может быть сложно вернуть все результаты запроса, особенно если их тысячи. Это создаёт нагрузку на сервер, на клиент, на сеть и часто является ненужным. Поэтому и придумали пагинацию.

Обычный способ разбиения на страницы это смещение или номер страницы. Вы делаете такой запрос:

GET /api/products?page=10{"items": [...100 products]}

а дальше такой:

GET /api/products?page=11{"items": [...another 100 products]}

В случае простого смещения получается ?offset=1000 и ?offset=1100 тот же старый суп, только разогретый. Здесь мы либо переходим прямо к SQL-запросу типа OFFSET 1000 LIMIT 100, либо умножаем на размер страницы (значение LIMIT). В любом случае, это неоптимальное решение, поскольку каждая база данных должна пропустить эту 1000 строк. А чтобы их пропустить, нужно их идентифицировать. Неважно, это PostgreSQL, ElasticSearch или MongoDB, она должна их упорядочить, пересчитать и выбросить.

Это ненужная работа. Но она повторяется снова и снова, так как такой дизайн легко реализовать вы непосредственно сопоставляете свой API с запросом к базе данных.

Что же тогда делать? Мы могли бы посмотреть, как устроены базы данных! У них есть понятие курсора это указатель на строку. Таким образом, вы можете сказать базе данных: Верни мне 100 строк после этой. И такой запрос гораздо удобнее для базы данных, так как высока вероятность, что вы идентифицируете строку по полю с индексом. И не нужно извлекать и пропускать эти строки, вы пройдёте прямо мимо них.

Пример:

GET /api/products{"items": [...100 products], "cursor": "qWe"}

API возвращает (непрозрачную) строку, которую затем можно использовать для получения следующей страницы:

GET /api/products?cursor=qWe{"items": [...100 products], "cursor": "qWr"}

С точки зрения реализации есть много вариантов. Как правило, у вас имеются некоторые критерии запроса, например, идентификатор товара (product id). В этом случае вы его кодируете с помощью некоторого обратимого алгоритма (скажем, хэш-идентификаторов). И при получении запроса с курсором вы декодируете его и генерируете запрос типа WHERE id > :cursor LIMIT 100.

Небольшое сравнение производительности. Вот результат смещения:

=# explain analyze select id from product offset 10000 limit 100;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------
Limit (cost=1114.26..1125.40 rows=100 width=4) (actual time=39.431..39.561 rows=100 loops=1)
-> Seq Scan on product (cost=0.00..1274406.22 rows=11437243 width=4) (actual time=0.015..39.123 rows=10100 loops=1)
Planning Time: 0.117 ms
Execution Time: 39.589 ms


А вот результат операции where:

=# explain analyze select id from product where id > 10000 limit 100;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.00..11.40 rows=100 width=4) (actual time=0.016..0.067 rows=100 loops=1)
-> Seq Scan on product (cost=0.00..1302999.32 rows=11429082 width=4) (actual time=0.015..0.052 rows=100 loops=1)
Filter: (id > 10000)
Planning Time: 0.164 ms
Execution Time: 0.094 ms


Разница в несколько порядков! Конечно, фактические цифры зависят от размера таблицы, от фильтров и реализации хранилища. Вот отличная статья с более подробной технической информацией, см. слайд 42 со сравнением производительности.


Конечно, никто не запрашивает товары по идентификатору их обычно запрашивают по какой-то релевантности (а затем по идентификатору в качестве решающего параметра). В реальном мире чтобы выбрать решение, нужно посмотреть на конкретные данные. Запросы можно упорядочить по идентификатору (так как он монотонно увеличивается). Товары из списка будущих покупок тоже можно упорядочить таким образом по времени составления списка. В нашем случае товары загружаются с ElasticSearch, который, естественно, поддерживает такой курсор.

Минус в том, что с помощью stateless API невозможно создать ссылку Предыдущая страница. В случае пагинации у пользователя невозможно обойти эту проблему. Так что если важно иметь кнопки предудущей/следующей страницы и Перейти непосредственно на страницу 10, то придётся использовать старый метод. Но в других случаях метод по курсору может значительно повысить производительность, особенно на очень больших таблицах с очень глубокой пагинацией.
Источник: habr.com
К списку статей
Опубликовано: 18.01.2021 22:06:54
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Sql

Api

Пагинация страниц

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru