Могу ли я запросить предыдущее время более эффективно в этом операторе Oracle SQL? - PullRequest
0 голосов
/ 08 мая 2019

У меня довольно простая таблица Oracle 9, состоящая из метки времени, номера элемента и значения.


DT_RECORDDATE    ITEMID     SYSTEMID    VALUE
2019-04-04       25         97          1
2019-04-05       19         55          1
2019-04-06       25         44          1
2019-04-03       44         29          2

Первичный ключ - DT_RECORDDATE и ITEMID.


Что я хотел бы сделать, так это получить самое последнее DT_RECORDDATE или, что еще лучше, самое последнее VALUE для каждого из моих идентификаторов предметов.

Для приведенной выше таблицы я должен получить что-то вроде этого ...

DT_RECORDDATE    ITEMID 
2019-04-05       19
2019-04-06       25
2019-04-03       44

Мое текущее решение состоит в том, чтобы получить самую высокую отметку даты.

SELECT MAX(DT_RECORDDATE), ITEMID 
FROM MYTABLE 
WHERE DT_RECORDDATE <= to_date('2019-05-05 10:00:00','YYYY-MM-DD hh24:mi:ss') 
  AND SYSTEMID=1 
GROUP BY ITEMID

Однако на больших столах это занимает МНОГО времени.

В результирующем наборе имеется 50 различных идентификаторов (больше, чем в таблице, но они отфильтрованы предложением WHERE).

Помимо создания новых ключей базы данных (что не слишком интересует администратора), есть ли способ улучшить время выполнения этого запроса? Запуск базы данных, содержащей несколько миллионов записей, занимает несколько секунд.

Я знаю, что люди, как правило, используют PARTITION и RANK() для улучшения производительности, но я должен признать, что я не очень хорошо знаком с тем, как они работают или будет ли это применимо в этом случае, так как Я не провел много времени с Oracle.

В настоящее время они не могут перейти на более современную версию Oracle Server.

1 Ответ

0 голосов
/ 08 мая 2019

Да, использование оконных функций обычно является наиболее эффективным решением. Следующее должно работать на вашей древней версии Oracle:

SELECT dt_recorddate, itemid, systemid, value
FROM (
  SELECT dt_recorddate, itemid, systemid, value, 
         row_number() over (partition by itemid order by dt_recorddate desc) as rn
  FROM mytable 
  WHERE dt_recorddate <= to_date('2019-05-05 10:00:00','YYYY-MM-DD hh24:mi:ss') 
    AND systemid=1 
) 
where rn = 1;

В качестве альтернативы следующие могут быть быстрее:

SELECT dt_recorddate, itemid, systemid, value
FROM mytable m
  JOIN (
    SELECT itemid, max(dt_recorddate) as max_date
    FROM mytable 
    WHERE dt_recorddate <= to_date('2019-05-05 10:00:00','YYYY-MM-DD hh24:mi:ss') 
      AND systemid=1 
    GROUP BY itemid
  ) x on x.itemid = m.itemid and x.max_date = dt_recorddate;

Я не помню, если Oracle 9 уже поддерживал более чистый явный оператор JOIN, если нет, то вам нужно переписать вышеприведенное в

SELECT dt_recorddate, itemid, systemid, value
FROM mytable m, 
     (SELECT itemid, max(dt_recorddate) as max_date
      FROM mytable 
      WHERE dt_recorddate <= to_date('2019-05-05 10:00:00','YYYY-MM-DD hh24:mi:ss') 
        AND systemid=1 
      GROUP BY itemid) x 
where x.itemid = m.itemid and x.max_date = dt_recorddate;
...