在oracle数据库中找到最新的日期

时间:2015-09-23 15:21:37

标签: sql oracle row-number rownum

我在oracle数据库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

解释计划:
enter image description here

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

解释计划:
enter image description here

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秒钟执行,但在第二次,我需要花费更多时间(我没有计算)。以下是解释计划:

enter image description here

此外,我也尝试过使用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)
            )

这个查询,计划给了我一个痛苦的结果。 enter image description here

3 个答案:

答案 0 :(得分:3)

为什么这么复杂?
如果你只需要最后一个日期,你可以使用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表不是太大而且您可能认为只需要探测具有最高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)

但是如果你需要在relatedasset表中做太多的探测来查找你需要的统计数据,你可能会有更差的表现。
更新帐户新计划
Sstan是对的,因为statistics表很大(71M),而减去结果很小(5),你只需要对相关的表格进行适当的索引。 我建议按relatedasset.assetid(relatedasset.linkid,relatedasset.assetid)进行索引,以避免进行表格扫描。

顺便说一下,你在第二个查询中错过了括号 (因为AND的优先级高于OR,因此需要在括号中使用CONDITION1CONDITION2来实现正确的WHERE条件),因此您的计划会更糟糕比它可能。但是无论如何使用这样的数据分布,即使是正确的版本也会比你的varian执行得更慢,并且具有适当的索引。

答案 1 :(得分:3)

由于relatedasset上的各种OR条件(IN和OR),DBMS决定执行全表扫描。这看似合理。那么我们可以优化什么呢?我们可以看到全表扫描只进行一次。查询表,按assetid分组并检查HAVING是否第一个条件对于任何记录都为真,第二个条件对于任何记录都是。

如果可能,您还可以使用并行提示使Oracle并行执行全表扫描。

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
);

答案 2 :(得分:2)

看起来你只是缺少索引。确保你有索引:

  • relatedasset.assetid
  • relatedasset.linkid

一旦这样做,那么您尝试的所有查询都会表现得更好。