sql - 如何在 SQL 中以高性能的方式使用 PARTITION BY 获取最新记录?
问题描述
在我们用于获取仪表板和报告信息的规范化 Oracle 12.2 数据库中,我们发现用户经常遇到想要了解每个分区的最新记录的数据的需求。在某些情况下,我们可以将数据过滤到较小的子集,而在其他情况下,我们需要整个数据集。在大多数情况下,用户希望同时了解多个分区的最新结果。在 oracle 中,典型的模式如下:
select * from (
select my_table.*,
row_number() over (partition by fk1, fk2, ... order by my_date desc) rn
from my_table
[where fk1 = 1234]
) where rn = 1
最初,为了方便起见,我们想将其抽象为视图,以便人们可以针对视图编写查询。我们尝试了这样的事情:
create view my_table_latest as (
select * from (
select my_table.*,
row_number() over (partition by fk1, fk2, ... order by my_date desc) rn
from my_table
) where rn = 1
)
select * from my_table_latest where fk1 = 1234
不幸的是,这有两个问题。首先,视图内部的分析函数似乎总是在应用任何过滤器之前对整个表进行计算。因此,无论使用什么过滤器和索引,都会扫描整个表。其次,当用于具有数百万条记录的表时,查询花费的时间比我们想要的要长。
鉴于我们希望我们的数据保持相对新鲜(在 10 分钟内),以高性能方式获取某些业务密钥的最新记录的最佳方法是什么?获取数据的方法应该隐藏在视图中,以便前端仪表板应用程序可以轻松使用它。
以下是我们的两个想法:
- 物化视图- 使用物化视图每 10 分钟重新计算一次结果。鉴于查询需要几分钟来计算,我们担心这可能无法正常工作。此外,根据我们在视图中包含分析查询的发现,我们怀疑由于使用了分析功能,使用更有效的刷新策略将不起作用。
- 随时跟踪- 鉴于我们可以访问写入数据的代码,并且数据始终处理最旧 -> 最新,我们可以轻松跟踪最新记录并将其保存到不同的表中。然后可以创建一个视图,该视图使用此信息并连接回原始表以获取其余的记录详细信息。“自定义索引”表类似于 (fk1, fk2, my_table.pk, date)。不幸的是,这需要更改代码。
解决方案
您可能会发现使用相关子查询更快:
select t.*
from my_table t
where t.my_date = (select max(t2.my_date)
from my_table t2
where t2.fk1 = t.fk1 and t2.fk2 = t.fk2 and . . .
);
当在外部查询中使用带有过滤功能的视图时,Oracle 可能会发现更容易对此进行优化。出于性能考虑,您需要在(fk1, fk2, . . ., my_date)
.
这假设日期对于给定的键组合不重复。
推荐阅读
- haskell - 为什么在这个 SBV/Z3 代码中 Int32 排序比整数排序慢得多?
- php - 我应该如何使用复选框声明控制器?
- tensorflow - 图模式下的 GRU/RNN 状态与急切执行模式
- excel - 用于搜索字符串的 VBA 代码,如果找到该字符串,则粘贴到另一个工作表中
- python-3.x - 如何对熊猫数据框中某些行的值进行排序?
- rust - 将 usize 转换为 f32
- c# - modelState.isValid 不检查所需的装饰属性
- ionic-framework - 我如何在 ionic 4 中设计此页面
- clips - CLIPS 谁是儿子或女儿,父亲或母亲,祖父或祖母
- amazon-web-services - Aws 认知链接