我可以在此Oracle SQL语句中更有效地请求以前的采样时间吗?

时间:2019-05-08 04:05:47

标签: sql oracle greatest-n-per-group oracle9i

我有一个相当简单的Oracle 9表,它由时间戳,itemid号和值组成。


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。


我想为我的每个商品ID获取最新的 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个不同的ID(比表中的ID还要多,但是由WHERE子句过滤掉了)。

除了创建新的数据库密钥(管理员对此不太感兴趣)之外,还有什么方法可以改善此查询的时间?在包含数百万条记录的数据库上运行需要几秒钟。

我知道人们倾向于使用PARTITIONRANK()来提高性能,但是我必须承认我对他们的工作方式以及它是否适用于他们并不超级熟悉。在这种情况下,因为我没有花很多时间在Oracle上。

它们当前无法升级到Oracle Server的更新版本。

1 个答案:

答案 0 :(得分:0)

是的,使用窗口函数通常是最有效的解决方案。以下内容也应适用于您的旧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;