Ответ 1
Давайте сначала поймем, почему смещение нумерации сбоев для больших наборов данных на примере.
Клиенты предоставляют два параметра ограничения для количества результатов и смещения и для смещения страницы. Например, при смещении = 40, ограничении = 20 мы можем указать базе данных вернуть следующие 20 элементов, пропустив первые 40.
Недостатки:
- Использование LIMIT OFFSET плохо масштабируется для больших наборов данных. По мере того как смещение увеличивается по мере продвижения в наборе данных, базе данных по-прежнему приходится считывать до смещения + счетчика строк с диска, прежде чем отбрасывать смещение и возвращать только счетные строки.
- Если элементы записываются в набор данных с высокой частотой, окно страницы становится ненадежным, потенциально пропуская или возвращая дублированные результаты.
Как Курсоры решают это?
Разбиение на основе курсора работает, возвращая указатель на определенный элемент в наборе данных. При последующих запросах сервер возвращает результаты после указанного указателя.
Мы будем использовать параметры next_cursor вместе с limit в качестве параметров, предоставленных клиентом в этом случае.
Предположим, мы хотим разбить страницы с самого последнего пользователя на самого старого пользователя. Когда клиент запрашивает первый раз, предположим, что мы выбираем первую страницу с помощью запроса:
SELECT * FROM users
WHERE team_id = %team_id
ORDER BY id DESC
LIMIT %limit
Где предел равен пределу плюс один, чтобы получить еще один результат, чем количество, указанное клиентом. Дополнительный результат не возвращается в наборе результатов, но мы используем идентификатор значения в качестве next_cursor.
Ответ от сервера будет:
{
"users": [...],
"next_cursor": "1234", # the user id of the extra result
}
Затем клиент предоставит next_cursor в качестве курсора во втором запросе.
SELECT * FROM users
WHERE team_id = %team_id
AND id <= %cursor
ORDER BY id DESC
LIMIT %limit
С этим мы обратились к недостаткам пагинации на основе смещения:
- Вместо того, чтобы окно вычислялось с нуля для каждого запроса на основе общего количества элементов, всегда выбирались следующие строки подсчета после определенной контрольной точки. Если элементы записываются в набор данных с высокой частотой, общая позиция курсора в наборе может измениться, но окно разбивки на страницы корректируется соответствующим образом.
- Это будет хорошо масштабироваться для больших наборов данных. Мы использовали предложение WHERE для извлечения строк со значениями идентификатора, меньшими, чем последний идентификатор на предыдущей странице. Это позволяет нам использовать индекс для столбца, и базе данных не нужно читать какие-либо строки, которые мы уже видели.
Для подробного объяснения вы можете посетить эту замечательную инженерную статью из slack!