Для большого набора данных нумерация на основе offset
становится медленной, и поэтому гораздо более быстрый способ - использовать пагинацию на основе курсора.По сути, это точка привязки, где база данных знает, как искать результаты с этого момента.Имея это в виду, вот проблема, с которой я сталкиваюсь:
У меня есть таблица tv_watchers
с автоинкрементом id
, mins_watching_tv
и user_id
(всего 20 строк скрипки ниже).В этом примере user_id
будет таким же 1
, поэтому не нужно беспокоиться об этом.Мы хотим отсортировать по количеству минут, потраченных на просмотр ТВ, от наивысшего к наименьшему.
Это легко сделать с помощью этого запроса:
SELECT * FROM tv_watchers
ORDER BY mins_watching_tv DESC, id ASC
Это вернет правильный порядок 20поля, упорядоченные таким образом, как мы хотим, по id:
2, 17, 1, 16, 15, 5, 6, 7, 8, 9, 10, 11, 12, 13, 20, 3, 4, 14, 19, 18
Проблема в том, что мы хотим разделить его на куски (мы называем их пакетами) по 5, поскольку мы хотим вернуть 5 результатов в порядкевыше.Мы делаем это, восстанавливая первые 6 результатов, возвращая первые 5 к пользователю, и с помощью 6-го, если он существует в качестве курсора (точки привязки), чтобы получить следующую партию из: Это возвращает первую партию правильно:
1019 *
6-й элемент здесь - это id 5
, который имеет mins_watching_tv
из 60
, поэтому, поскольку это курсор, мы используем его, чтобы получить следующие 6 следующим образом:
-- (Batch 2) 5, 6, 7, 8, 9, 10
SELECT * FROM tv_watchers
WHERE mins_watching_tv <= 60 OR id=5
ORDER BY mins_watching_tv DESC, id ASC
LIMIT 6
6-й элемент здесь - это id 10
, который также имеет mins_watching_tv
из 60
, поэтому, поскольку это курсор, мы используем его, чтобы получить следующие 6 следующим образом:
-- (Batch 3 should be) 10, 11, 12, 13, 20, 3
-- (Batch 3 returns incorrectly) 5, 6, 7, 8, 9, 10
SELECT * FROM tv_watchers
WHERE mins_watching_tv <= 60 OR id=10
ORDER BY mins_watching_tv DESC, id ASC
LIMIT 6
Нопроблема заключается в том, что возвращаемые результаты не являются правильными, возвращаются неверные 3 идентификатора партии, указанные в комментарии выше.Я уверен, что это связано с частью WHERE
, кажется, что она забирает часть mins_watching_tv <= 60
, но часть id=10
здесь, чтобы база данных знала, что нужно получить результаты с этой точки привязки 60 минут и идентификатора10, но это не работает правильно.
Окончательные результаты партии должны выглядеть следующим образом:
-- (Batch 4) 3, 4, 14, 19, 18
Я установил sql fiddle здесь , чтобы показать проблему,Как можно исправить запрос, чтобы он учитывал комбинацию курсоров mins_watching_tv
в сочетании с id
, чтобы возвращать правильные результаты в пакетах?