Oracle慢速RANK功能

时间:2016-06-16 18:57:26

标签: sql oracle performance rank dense-rank

我的应用程序使用必须保持通用的视图(无过滤器),其中包括分析函数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中的每个唯一条目创建分区?还有其他方法可以避免吗?关于如何加快速度的任何建议?

1 个答案:

答案 0 :(得分:0)

正如评论中所提到的,在视图中使用您的分析功能,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
)

那么,有没有办法让它更快?也许

  1. 如果表是分区的,那就是使用并行查询的想法。
  2. 索引有帮助吗?
  3. 不是通常意义上的。由于视图本身没有条件,它将进行全表扫描以考虑排名的所有行,并且在应用WHERE子句时,使用索引进行过滤已经太晚了。

    但是,如果你有一个&#34;覆盖的索引&#34;查询,即只有正在使用的列的索引(例如,FIELD1,FIELD2,FIELD3的顺序),索引可以用作表的较小版本(而不是FULL TABLE SCAN,计划将显示INDEX快速全扫描。)作为奖励,因为它已经排序,它可以有效地计算FIELD1上的分区,然后在每个分区内的FIELD2上进行排序。

    1. 另一种选择是将其作为物化视图,但如果您的数据经常变化,那么保持最新状态可能会非常痛苦。

    2. 最后一个想法是与“穷人”相似的东西&#34;在分区选项的日期之前使用的分区。 (对不起,我找不到描述这个的好链接,但也许你以前听说过。)

    3. 在以下情况下,这只是一个选项:

      1. 您的分区列具有相对较少的不同值
      2. 这些价值观不会改变
      3. 您知道可以使用哪些分区值来隔离查询中的数据
      4. Oracle愿意在可行的情况下推送谓词
      5. 鉴于Oracle在涉及分析函数时似乎不利于推断谓词,我并没有给出很高的成功概率。

        如果您想了解更多相关信息,请与我们联系。