Лучший способ получить непрерывный список с PostgreSQL в Интернете - PullRequest
8 голосов
/ 13 октября 2011

Я делаю API через HTTP, который выбирает большие строки из PostgreSQL с разбивкой на страницы.В обычных случаях я обычно использую нумерацию страниц через это наивное OFFET / LIMIT предложение.Тем не менее, в этом случае существуют некоторые особые требования:

  • Есть много строк, но я считаю, что пользователи не могут достичь конца (представьте график Twitter).
  • Страницы не должныбыть доступным случайным образом, но последовательно.
  • API будет возвращать URL-адрес, содержащий маркер курсора, который указывает на страницу непрерывных фрагментов.
  • Токены курсора не должны существовать постоянно, но в течение некоторого времени.
  • Его порядок часто колеблется (например, рейтинг Reddit), однако непрерывные курсоры должны сохранять их последовательный порядок.

Как мне выполнить миссию?Я готов изменить всю схему базы данных для нее!

Ответы [ 2 ]

6 голосов
/ 20 октября 2011

Если предположить, что колеблется только порядок результатов, а не данные в строках, ответ Фредрика имеет смысл. Однако я бы предложил следующие дополнения:

  • сохранить список идентификаторов в таблице postgresql, используя тип array , а не в памяти. Выполнение этого в памяти, если вы не используете осторожно что-то вроде redis с автоматическим истечением и ограничением памяти, настроит вас на атаку потребления памяти DOS. Я думаю, это будет выглядеть примерно так:

    create table foo_paging_cursor (
      cursor_token ..., -- probably a uuid is best or timestamp (see below)
      result_ids integer[], -- or text[] if you have non-integer ids
      expiry_time TIMESTAMP
    );
    
  • Вам необходимо решить, можно ли совместно использовать cursor_token и result_ids для пользователей, чтобы уменьшить ваши потребности в хранилище и время, необходимое для выполнения начального запроса для каждого пользователя. Если им можно поделиться, выберите окно кэша, скажем, 1 или 5 минут, а затем при новом запросе создайте cache_token для этого периода времени, а затем проверьте, были ли уже рассчитаны идентификаторы результатов для этого токена. Если нет, добавьте новую строку для этого токена. Возможно, вам следует добавить блокировку вокруг кода проверки / вставки для обработки одновременных запросов на новый токен.

  • Запланируйте фоновое задание, которое удаляет старые токены / результаты, и убедитесь, что ваш клиентский код может обрабатывать любые ошибки, связанные с просроченными / недействительными токенами.

Даже не думайте использовать для этого реальные курсоры БД.

Хранение идентификаторов результатов в списках Redis - это еще один способ справиться с этим (см. Команду LRANGE ), но будьте осторожны с истечением срока действия и использованием памяти, если вы идете по этому пути. Ваш ключ Redis будет курсором_token, а идентификаторы будут членами списка.

1 голос
/ 15 октября 2011

Я абсолютно знаю ничего о PostgreSQL, но я довольно приличный разработчик SQL Server, так что я бы хотел все равно попробовать:)

Как вы ожидаете, сколько строк / страниц максимально просмотрит пользователь за сеанс? Например, если вы ожидаете, что пользователь просматривает максимум 10 страниц для каждого сеанса [каждая страница содержит 50 строк], вы можете взять этот максимум и настроить веб-сервис таким образом, чтобы при запросе пользователем первой страницы вы кэшировали 10 * 50 строк (или только Id: s для строк, зависит от того, сколько у вас памяти / одновременных пользователей).

Это, безусловно, поможет ускорить работу вашего веб-сервиса разными способами. И это довольно легко реализовать. Итак:

  • Когда пользователь запрашивает данные со страницы № 1. Запустите запрос (в комплекте с order by, проверками соединения и т. Д.), Сохраните все идентификаторы в массиве (но не более 500 идентификаторов). Возвращает datarows, которые соответствуют id: s в массиве в позициях 0-9.
  • Когда пользователь запрашивает страницу № 2-10. Возвращает datarows, которые соответствуют id: s в массиве в положениях (страница-1) * 50 - (страница) * 50-1.

Вы также можете увеличивать числа, массив из 500 int: s будет занимать только 2 КБ памяти, но это также зависит от того, насколько быстро вы хотите получить свой первоначальный запрос / ответ.

Я использовал аналогичную технику на живом веб-сайте, и когда пользователь продолжил просматривать страницу 10, я просто переключился на запросы. Я думаю, что другое решение будет продолжать расширять / заполнять массив. (Выполнение запроса снова, но исключая уже включенные идентификаторы: s).

В любом случае, надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...