Oracle 慢 RANK 函数

Posted

技术标签:

【中文标题】Oracle 慢 RANK 函数【英文标题】:Oracle slow RANK function 【发布时间】:2016-10-18 10:49:41 【问题描述】:

我的应用程序使用的视图必须保持通用(无过滤器),并且包括分析函数 RANKDENSE_RANK。例如我有一个视图MYVIEW:

SELECT 
RANK() OVER (PARTITION BY FIELD1 ORDER BY FIELD2) RANK, 
FIELD2, 
FIELD3
FROM TABLE1;

然后我的应用程序在运行时应用必要的过滤器,即

SELECT * FROM MYVIEW WHERE FIELD3 IN ('a','b','c');

我的查询在没有 RANK 功能的情况下非常快,但使用它时速度非常慢(2 分钟以上)(我得到了正确的结果,只是速度很慢)。基础表有 250,000 多行,我无法控制它的设计。我无法进一步划分它。那么它是否很慢,因为每次调用视图时它都会为 FIELD1 中的每个唯一条目创建分区?还有什么办法可以避免吗?有关如何加快速度的任何建议?

【问题讨论】:

您是否尝试过查看查询计划? 我有点期待它首先应用过滤器(谓词推送)并将排名应用于匹配的行。但执行计划将揭示正在发生的事情。您是否获得了您期望的排名值 - 即它们是否在结果集上是连续的,或者在应用过滤器之前它们是否存在被评估的差距? (你想要哪个?) @Alex Pole,FIELD3 IN ('a','b','c'); 条件的谓词推送在这种情况下不起作用,因为这是一种物化子查询:SELECT ... FROM (subquery/view that numbers rows ) WHERE FIELD3 IN ('a','b','c'); - 此查询必须首先为所有行分配数字,然后选择一些行,但会改变数字。我猜table1( FIELD1, FIELD2 ) 上的简单多列索引可以加快查询速度。 @kordiko - 我的期望经常是错误的 *8-) 我不确定排名是否总是首先出现(部分是我所要求的)所以你已经保存了我的测试来找出答案。 物化视图?不知道这是否可能,因为我正在使用的 RDBMS 不允许在物化视图中使用分析功能。 :( 【参考方案1】:

正如 cmets 中提到的,在视图中使用您的分析功能,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 在涉及分析函数时似乎不赞成推动谓词,因此我不认为这有很高的成功概率。

如果您想了解更多信息,请告诉我。

【讨论】:

以上是关于Oracle 慢 RANK 函数的主要内容,如果未能解决你的问题,请参考以下文章

oracle sql rank函数取排序值

[转]oracle分析函数Rank, Dense_rank, row_number

Oracle 中 rownumrow_number()rank()dense_rank() 函数的用法

Oracle-- (RANK) 排名函数

oracle 如何将某表用rank函数排序出来的值,update到该表中的某个字段

Oracle排名函数(Rank)实例详解