Oracle SQL выбирает отдельный запрос для возврата определенного количества строк

У меня есть таблица в базе данных Oracle с столбцом отметки времени nextTime и столбцом строки destName. Также есть больше столбцов, но только эти два имеют отношение в этом случае. Я пытаюсь разработать запрос, который будет возвращать различные destName, имеющие nextTime в течение определенного интервала, и возвращаемое количество строк должно быть максимум одна тысяча. Если в интервале более тысячи различных destName, я хочу, чтобы запрос возвращал тысячу строк, больше или меньше.

У меня фактически есть запрос, который работает, но он слишком медленный:

select destName 
from (select /*+ index(tblDestNames tbldestnames_destname)*/ distinct destName
from (select /*+ index(tblDestNames tbldestnames_nextTime)*/ destName
from tblDestNames 
where nextTime < :1 and nextTime >= :2 and destName is not null)) 
where rownum <= 1000; 

Любые идеи о том, как разработать более умный запрос или как его оптимизировать, очень ценятся.

2 ответа

Решение

Я не уверен, что есть причина не упрощать запрос к этому:

select destName 
from (
    select distinct destName
    from tblDestNames 
    where nextTime < :1 and nextTime >= :2 and destName is not null
    )
where rownum <= 1000; 

Однако это не решит проблему с производительностью. Проблема заключается в следующем:

where rownum <= 1000

Заменив rownum на "rank" и "over", вы получите что-то вроде:

select distinct destName
from (
    select
       destName
    from
       (select destName, rank()
        over (order by destName desc ) rnk
        from tblDestNames
        where nextTime < :1 and nextTime >= :2 and destName is not null) 
    where rnk <= 1000;
    )

Бонус в том, что с помощью "over" вы выбираете порядок результатов, которые будут отображаться, и тех, которые не будут отображаться.

РЕДАКТИРОВАТЬ: На самом деле это может быть дополнительно упрощено в:

select
   distinct destName
from
   (select destName, rank()
    over (order by destName desc ) rnk
    from tblDestNames
    where nextTime < :1 and nextTime >= :2 and destName is not null) 
where rnk <= 1000;

Вещи, которые я подобрал

  1. Вы должны оставить оптимизацию плана выполнения СУБД, если вы действительно не знаете лучше
  2. Нет необходимости возвращать повторяющиеся имена из самого внутреннего подзапроса

Упрощенный запрос с немного другой семантикой:

SELECT destName
FROM (SELECT DISTINCT destName
      FROM tblDestNames
      WHERE destName IS NOT NULL 
        AND nextTime NOT BETWEEN :1 and :2)
WHERE rownum <= 1000;

Обратите внимание, что BETWEEN включительно то есть x BETWEEN y AND z равняется y <= x <= z, Чтобы исключить верхнюю границу, вы должны будете либо сделать это так, как делали, либо уменьшить значение параметра:2 на единицу, равную единице nextTime.

Другие вопросы по тегам