Распространенным решением для высокопроизводительной нумерации страниц является использование индексированного поля, начиная каждую новую «страницу» с последнего значения предыдущей страницы. Например, с таким набором данных (при условии, что Category и ID являются первичным ключом):
Category | ID | Name
Red | 10 | Bob Jones
Red | 14 | Sam Smith
Red | 16 | Jill White
Blue | 10 | Mike Green
Blue | 16 | Mary Brown
Предполагая (довольно небольшой) размер страницы 1, если мы хотим вернуть все записи категории Red
(предположим, ORDER BY Category, ID):
SELECT * FROM table WHERE Category='Red' AND ID>'00' (1st page, returns Bob Jones)
SELECT * FROM table WHERE Category='Red' AND ID>'10' (2nd page, returns Sam Smith)
SELECT * FROM table WHERE Category='Red' AND ID>'14' (3rd page, returns Jill White)
Это работает, потому что по пагинации «keyset» использует только поле идентификатора (и оно также будет работать с несколькими полями, если идентификатор был глобально уникальным, что не является).
Но если я хочу вернуть все красные и синие записи (при условии, что таблица также содержит другие категории), по-прежнему по одной странице за раз (предположим, ORDER BY Category, ID):
SELECT * FROM table WHERE Category IN ['Red', 'Blue'] AND Category>'' AND ID>'00' (1st page, returns Bob Jones)
SELECT * FROM table WHERE Category IN ['Red', 'Blue'] AND Category>'Red' AND ID>'10' (2nd page, returns Sam Smith, but skips Mike Green)
В PostgreSQL и некоторых других есть синтаксис предиката «значения строки», который поддерживает это (предположим, ORDER BY Category, ID):
SELECT * FROM table WHERE (Category, ID) > ('', '00') (1st page, returns Bob Jones)
SELECT * FROM table WHERE (Category, ID) > ('Red', '10') (2nd page, returns Sam Smith)
Это работает, потому что и категория, и идентификатор рассматриваются как одно составное значение для целей теста. Но я не использую PostgreSQL или базу данных, которая поддерживает «значения строк». Таким образом, вопрос заключается в том, есть ли альтернативное решение, которое будет работать для этого (есть ли 2 или n полей)? Чтобы он работал для разбивки на несколько переменных полей, мне нужно создать предикат, который всегда найдет «следующую запись» в порядке сортировки по нескольким полям.
PS: нумерация страниц OFFSET / LIMIT или SKIP / LIMIT, конечно, работает, но ни одна из них неэффективна для больших наборов данных, поэтому я пытаюсь использовать нумерацию "keyset".