Общий предикат SQL, используемый для разбиения на страницы набора ключей в нескольких полях - PullRequest
1 голос
/ 23 июня 2019

Распространенным решением для высокопроизводительной нумерации страниц является использование индексированного поля, начиная каждую новую «страницу» с последнего значения предыдущей страницы. Например, с таким набором данных (при условии, что 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".

1 Ответ

0 голосов
/ 23 июня 2019

Вы всегда можете сформулировать предикат:

(x, y) > (a, b)

как:

x >= a and (x = a and y > b or x > a)

Обратите внимание, что первый префект x >= a поощряет (не гарантирует) использование индексана этом столбце.То есть он становится «предикатом доступа».Второй x = a and y > b or x > a отфильтровывает избыточные строки, фактически превращаясь в «предикат фильтрации».

Этот способ формулирования предикатов «неравенство кортежей» способствует использованию индексов.Однако они становятся все более сложными, если вы сравниваете 3, 4 или более столбцов.

...