在oracle数据库中查找最新日期

Find the lastest date in oracle database

我在oracle database ver.10的查询遇到了很大的麻烦。我想要的是找到最后一个日期 dateofstat 我尝试了很多解决方案,但它有效,但需要太多时间。 - 使用 rownum
- 使用 row_number()
- 使用 rank()

有我的尝试:
1。 rownum

select dateofstat from (
select  stat.dateofstat from dhg.statistics stat
join (
  select distinct assetid from dhg.relatedasset
     where (`CONDITION1`)
  MINUS
  select distinct assetid from dhg.relatedasset
 where (`CONDITION2`)
) grs 
on stat.assetid = grs.assetid
order by stat.dateofstat desc
)where rownum = 1

解释计划:

row_number()

select dateofstat from (
  select stat.dateofstat,
    row_number() over (order by stat.dateofstat desc) rnumber
  from dhg.statistics stat
  join (
    select distinct assetid from dhg.relatedasset
    where (`CONDITION1`)
    MINUS
    select distinct assetid from dhg.relatedasset
    where (`CONDITION2`)
  ) grs 
  on stat.assetid = grs.assetid
) where rnumber = 1

解释计划:

rank():我试过这个解决方案,但它给出了重复的排名数字,因此,我认为我不应该使用这个解决方案来找到最高的。

我不知道我现在该怎么办,真的需要帮助。为了测试,我在 emacs 上使用 sqlplus,没有 rownum 我用了不到 3 秒的时间来获取这个查询的第一行。

select  stat.dateofstat from dhg.statistics stat
join (
  select distinct assetid from dhg.relatedasset
     where (`CONDITION1`)
  MINUS
  select distinct assetid from dhg.relatedasset
 where (`CONDITION2`)
) grs 
on stat.assetid = grs.assetid
order by stat.dateofstat desc

我想知道我是否可以通过此调整获得任何变通解决方案。

从@ANTON 更新解决方案状态

select  max(stat.dateofstat) from dhg.statistics stat
join (
 select distinct assetid from dhg.relatedasset
     where relatedasset.assetid in (191759.0, 3.0, 5.0, 98.0, 99.0)
   or relatedasset.linkid in (3232.0, 1049.0, 1057.0, 1067.0, 102.0, 1032.0, 104.0, 105.0, 1051.0)
 MINUS
 select distinct assetid from dhg.relatedasset
     where relatedasset.assetid in (192106.0, 1014.0, 10302.0)
   or relatedasset.linkid in (210.0, 737.0, 126.0, 1053.0, 1054.0, 119.0, 3133.0)
 ) grs 
 on stat.assetid = grs.assetid

我必须说,我确实工作过一次,非常奇怪的行为。第一次执行我只用了 3 秒来执行,但在第二次执行时,我花费了更多的时间(我没有计算)。以下是解释计划:

此外,我也试过使用existnot exists的第二种解决方案,但效果不佳。

select  max(stat.dateofstat)
from dhg.statistics stat
where exists(select *
           from dhg.relatedasset rasset
           where stat.assetid = rasset.assetid
           and rasset.assetid in (191759.0, 3.0, 5.0, 98.0, 99.0)
           or rasset.linkid in (3232.0, 1049.0, 1057.0, 1067.0, 102.0, 1032.0, 104.0, 105.0, 1051.0)
            )
and not exists (select *
           from dhg.relatedasset rasset2
           where stat.assetid = rasset2.assetid
           and rasset2.assetid in (192106.0, 1014.0, 10302.0)
           or rasset2.linkid in (210.0, 737.0, 126.0, 1053.0, 1054.0, 119.0, 3133.0)
            )

这个查询,计划给我一个痛苦的结果。

为什么这么复杂?
如果你只需要最后一个日期,你可以使用 max() 函数:

select  max(stat.dateofstat)
from dhg.statistics stat
join (
  select distinct assetid from dhg.relatedasset
     where (`CONDITION1`)
  MINUS
  select distinct assetid from dhg.relatedasset
 where (`CONDITION2`)
) grs 
on stat.assetid = grs.assetid

如果 dhg.statistics table 不是太大并且您可能假设您只需要探测几个具有最高 dateofstat 的记录以找到满足您的相关资产要求的记录,那么您可以重写查询这个:

select  max(stat.dateofstat)
from dhg.statistics stat
where exists(select *
               from dhg.relatedasset asset1
              where (`CONDITION1`)
                and stat.assetid = asset1.assetid)
 and not exists (select *
               from dhg.relatedasset asset2
              where (`CONDITION2`)
                and stat.assetid = asset2.assetid)

但如果您需要在相关资产中进行过多探测 table 才能找到您需要的统计数据,您的性能可能会更差。
更新考虑新计划
Sstan 是对的,因为 statistics table 很大(71M),减去结果很小(5),你只需要对 relatedasset table
进行适当的索引 我建议通过 relatedasset.assetid(relatedasset.linkid,relatedasset.assetid) 进行索引以避免 table 扫描。

顺便说一下,你在第二个查询中漏掉了括号
(因为 ANDOR 具有更高的优先级,所以需要将 CONDITION1CONDITION2 放在括号中才能获得正确的 WHERE 条件),
所以你有很多计划比它可能更糟。但是无论如何,对于这样的数据分布,即使是正确的版本也会比具有适当索引的 varian 执行得更慢。

您似乎只是缺少索引。确保你有索引:

  • relatedasset.assetid
  • relatedasset.linkid

一旦你这样做,那么你所有尝试的查询都会执行得更好。

由于 relatedasset 上的各种 OR 条件(IN 和 OR),DBMS 决定执行完整的 table 扫描。这似乎是合理的。那么我们可以优化什么呢?我们可以确保完整的 table 扫描仅完成一次。查询 table,按 assetid 分组并检查 HAVING 是否第一个条件对任何记录为真,第二个条件对 none.

如果可能,您还可以使用并行提示让 Oracle 并行执行完整的 table 扫描。

select  max(dateofstat)
from dhg.statistics
where assetid in
(
  select /*+ parallel(relatedasset,4) */ assetid
  from dhg.relatedasset 
  group by assetid
  having 
    max( case when assetid in (191759.0, 3.0, 5.0, 98.0, 99.0) 
                or linkid in (3232.0, 1049.0, 1057.0, 1067.0, 102.0, 1032.0, 104.0, 105.0, 1051.0) 
         then 1 else 0 end ) = 1
  and
    max( case when assetid in (192106.0, 1014.0, 10302.0)
                or linkid in (210.0, 737.0, 126.0, 1053.0, 1054.0, 119.0, 3133.0) 
         then 1 else 0 end ) = 0
);