2017-02-16 1 views
2

У меня есть People стол (Id, first_name, last_name), где первичный ключ id. Я хочу, чтобы посмотреть первые N людей в таблице, заказанной (last_name, first_name, Id). В некоторых случаях мне нужно искать следующих N людей и так далее. Я хочу сделать это эффективно. Каков наилучший способ сделать это?Как реализовать разбивку на страницы?

ответ

3

Есть два основных способа:

  • Используйте LIMIT и OFFSET
  • Используйте LIMIT и ключ-из-предыдущей-странице

СМЕЩ стратегия позволяет читать любую страницу, но неэффективен, так как каждый раз, когда выполняется запрос, он должен читать строки со всех предыдущих страниц. Это проще всего реализовать и может быть приемлемой стратегией (особенно если вы хотите только первые несколько страниц), но в целом это не рекомендуется. Стратегия «предыдущая страница» требует, чтобы страницы читались по порядку, но эффективнее, потому что каждая страница читает только нужные ей строки.

Итак, давайте начнем с исходным запросом для выборки результатов из таблицы заказанного (LastName, FirstName, Id):

SELECT 
    t.id, 
    t.first_name, 
    t.last_name 
FROM 
    People as t 
ORDER BY 
    t.last_name, 
    t.first_name, 
    t.id 
LIMIT 
    @limit_rows 

Вы, вероятно, хотите, чтобы убедиться, что ваши запросы все просмотра последовательного снимка данных вашей базы данных, так что вы» Я хочу, чтобы ваша последовательность запросов всегда читалась с той же метки времени. Самый простой способ выполнить это - для первого запроса быть транзакцией ReadOnly с returnReadTimestamp, установленной в true. Затем ваши последующие запросы также могут быть транзакциями ReadOnly, и они должны использовать ту же метку времени, которая была возвращена исходным запросом в качестве readTimestamp. Обратите внимание: какой бы подход вы ни выбрали - предложение ORDER BY имеет жизненно важное значение для обеспечения согласованных результатов в вашей последовательности запросов. Предположим, что последняя строка вернулась: (1709, "John", "Smith"). Тогда ваша первая попытка запроса, чтобы получить следующую страницу результатов может выглядеть следующим образом:

SELECT 
    t.id, 
    t.first_name, 
    t.last_name 
FROM 
    People as t 
WHERE 
    t.last_name > "Smith" 
    OR 
    (t.last_name = "Smith" and t.first_name > "John") 
    OR 
    (t.last_name = "Smith" and t.first_name = "John" AND t.id > 1709) 
ORDER BY 
    t.last_name, 
    t.first_name, 
    t.id 
LIMIT 
    @limit_rows 

Средний WHERE пункт является новым. Но писать этот предикат сложнее, чем вы думаете. Возможно, вам придется обрабатывать значения NULL. Вы должны обрабатывать случай, когда несколько человек по имени Джон Смит имеют разные значения id. И вам нужно быть очень осторожным с числами с плавающей запятой и значениями NaN. API-интерфейс API-интерфейса Cloud Spanner также может быть полезен в таких случаях, поскольку он упрощает разбиение на диапазон сканирования по таблице.

+0

Привет Майк, спасибо, что разместили это. Если вы используете моментальные снимки и поставляете временную метку, почему необходимо добавлять все те, где существуют ограничения. не могли бы вы просто сказать t.id> 1709? Или вы пытаетесь осветить случай, когда моментальный снимок истек из-за сбора мусора? – Bradford

+0

Уборка мусора здесь не имеет значения. Причина дополнительных ограничений заключается в том, что в вопросе говорится, что мы хотим вернуть результаты запроса в порядке (Lastname, Firstname, Id), который не совпадает с порядком первичного ключа. Обратите внимание, что может быть результат, t.id которого меньше 1709, который все еще является необходимым результатом (например, «Уилкс», «Боб», 805) –

0

Оба MySQL и PostgreSQL поддерживают действительно классную функцию, которая называется OFFSET, которая обычно используется с предложением LIMIT.

Предложение LIMIT используется для ограничения числа результатов, возвращаемых в инструкции SQL. Так что если у вас есть 1000 строк в таблице, но только хочу вернуть первые 10, вы могли бы сделать что-то вроде этого:

SELECT column FROM table LIMIT 10 

Это похоже на TOP статьи на Microsoft SQL Server. Однако предложение LIMIT всегда идет в конце запроса в MySQL и PostgreSQL.

Теперь предположим, что вы хотели показать результаты 11-20.С OFFSET ключевым словом его так же просто, следующий запрос будет делать:

SELECT column FROM table LIMIT 10 OFFSET 10 

Это позволяет легко кодировать многоканальные результаты страницы или нумерацию страницы с SQL. Часто используемый подход заключается в выборе всех записей, а затем фильтрации через них на уровне сервера приложений, а не непосредственно в базе данных. Как вы могли бы себе представить, что это в базе данных дает гораздо лучшую производительность.

Смежные вопросы