ЗАКАЗЫВАЙТЕ ЗАРАНЕЕ, ГДЕ — альтернативы?

#sql #postgresql

Вопрос:

Я использую базу данных PostgreSQL (12.8).

Учитывая events сортировку по start_time , я хотел бы получить следующие 10 события после события с id = 10 помощью .

Моя первая идея была примерно такой:

 SELECT *
FROM events
ORDER BY start_time
WHERE id > 10
LIMIT 10;
 

Однако это не работает, потому WHERE что предложение-всегда применяется перед ORDER BY предложением -. Другими словами, сначала выбираются все события , у которых есть an id > 10 , и только оставшиеся события затем упорядочиваются по start_time .

Затем я придумал выражение CTE. Если запись с идентификатором 10 имеет row_number 3 :

 WITH ordered_events AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY start_time DESC) AS row_number
  FROM events
)
SELECT *
FROM ordered_events
WHERE row_number > 3
LIMIT 10;
 

Это работает так, как хотелось бы, если бы я знал об row_number этом заранее. Однако я знаю только идентификатор, id = 10 т. Е.

а) В идеале я бы сделал что-то подобное (однако я не знаю, есть ли какой-либо способ написать такое выражение):

 WITH ordered_events AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY start_time DESC) AS row_number
  FROM events
)
SELECT *
FROM ordered_events
WHERE row_number > (row_number of row where the ID is 10) # <------
LIMIT 10;
 

б) Единственная альтернатива, которую я придумал, — это сначала получить row_number данные для всех записей, а затем выполнить второй запрос.

Первый запрос:

 SELECT id, ROW_NUMBER() OVER (ORDER BY start_time DESC) AS row_number
FROM events;
 

Теперь я знаю, что row_number для записи с идентификатором 10 есть 3 . Таким образом, у меня достаточно информации, чтобы выполнить запрос с выражением CTE, как описано выше. Однако производительность низкая, потому что мне нужно извлечь все записи из events первого запроса.

Я был бы очень признателен, если бы вы помогли мне найти (эффективный) способ сделать это.

Комментарии:

1. «…потому что предложение WHERE всегда применяется перед предложением ORDER BY…»-неверно. Ядра баз данных выполняют запрос, используя внутренние стратегии. То, о чем вы говорите, вероятно, преподается как педагогический инструмент, но реальные рабочие механизмы так не работают.

Ответ №1:

Вам нужны только строки со временем начала меньше, чем время начала идентификатора 10. Используйте WHERE для этого предложение.

 select *
from events where start_time < (select start_time from events where id = 10)
order by start_time desc
limit 10;
 

Этот запрос может извлечь выгоду из индекса start_time. (Я считаю само собой разумеющимся, что уже существует индекс ID, позволяющий быстро найти строку с идентификатором 10.)