我在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
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秒钟执行,但在第二次,我需要花费更多时间(我没有计算)。以下是解释计划:
此外,我也尝试过使用exist
和not 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)
)
答案 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
,因此需要在括号中使用CONDITION1
和CONDITION2
来实现正确的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
一旦这样做,那么您尝试的所有查询都会表现得更好。