正如评论中提到的那样,使用视图中的分析功能,Oracle 不能采取任何捷径(谓词推送),因为
- 在您看来,您已经与 Oracle 达成了一项协议:无论何时访问视图,RANK 都应基于表中的所有行 - 未指定 WHERE 子句
- 查询视图时,“外部”WHERE 子句永远不应影响视图生成的行的外观,而只影响该行是否保留
- 分析函数查看其他行以生成值,因此如果您更改这些行(过滤),您可以更改值 - 推送谓词很容易影响这些函数生成的值
- 如果发生这种情况,您的视图结果可能会变得非常不一致(仅取决于优化器选择评估查询的方式)
因此,根据您提供的详细信息,您的查询需要像这样评估:
SELECT *
FROM (
SELECT
RANK() OVER (PARTITION BY FIELD1 ORDER BY FIELD2) RANK,
FIELD2,
FIELD3
FROM TABLE1
) myview
WHERE <condition>; -- rankings are not affected by external conditions
而不是这个:
SELECT * FROM (
SELECT
RANK() OVER (PARTITION BY FIELD1 ORDER BY FIELD2) RANK,
FIELD2,
FIELD3
FROM TABLE1
WHERE FIELD3 IN ('a','b','c') -- ranking is affected by the conditions
)
那么,有没有办法让它更快呢?也许。
- 如果表是分区的,就有使用并行查询的想法。
- 索引有帮助吗?
不是通常意义上的。由于视图本身没有条件,因此它将执行全表扫描以考虑所有行的排名,并且在应用 WHERE 子句时,使用索引进行过滤为时已晚。
但是,如果您有一个“覆盖”查询的索引,即仅对正在使用的列有一个索引(例如 FIELD1、FIELD2、FIELD3 的顺序),则可以将索引用作表的较小版本(而不是 FULL TABLE SCAN,该计划将显示 INDEX FAST FULL SCAN。)作为奖励,由于它已经排序,它可以有效地计算 FIELD1 上的分区,然后在每个分区中对 FIELD2 排序。
另一种选择是将其设为物化视图,但如果您的数据经常更改,那么保持最新可能会很痛苦。
最后一个想法是类似于在分区选项出现之前使用的“穷人”分区。(对不起,我找不到描述这个的好链接,但也许你以前听说过。)
这实际上只是一种选择,如果:
- 您的分区列具有相对较少的不同值
- 这些值不会改变
- 您知道可以使用哪些分区值来隔离查询中的数据
- Oracle 愿意在安全的情况下推送谓词
鉴于 Oracle 在涉及分析功能时似乎不赞成推动谓词,因此我不认为这有很高的成功概率。
如果您想了解更多信息,请告诉我。