在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 秒来执行,但在第二次执行时,我花费了更多的时间(我没有计算)。以下是解释计划:
此外,我也试过使用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)
)
这个查询,计划给我一个痛苦的结果。
为什么这么复杂?
如果你只需要最后一个日期,你可以使用 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 扫描。
顺便说一下,你在第二个查询中漏掉了括号
(因为 AND
比 OR
具有更高的优先级,所以需要将 CONDITION1
和 CONDITION2
放在括号中才能获得正确的 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
);
我在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 秒来执行,但在第二次执行时,我花费了更多的时间(我没有计算)。以下是解释计划:
此外,我也试过使用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)
)
这个查询,计划给我一个痛苦的结果。
为什么这么复杂?
如果你只需要最后一个日期,你可以使用 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 扫描。
顺便说一下,你在第二个查询中漏掉了括号
(因为 AND
比 OR
具有更高的优先级,所以需要将 CONDITION1
和 CONDITION2
放在括号中才能获得正确的 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
);