使用ROWNUM进行Oracle查询优化

时间:2015-06-10 01:44:05

标签: oracle performance rownum

这个问题现在没有用了

我重新计算了表格中的统计数据,添加了新的指数,并重新分析了现有指数。这完全改变了我的结果,并使我的大多数发现无效。在这一点上,我发现了一个新的查询,它具有足够的性能,不需要任何ROWNUM技巧。

此外,我认为值得指出的是,下面的查询,如书面所示,并不能保证给出我想要的结果。将DISTINCT添加到中间查询可能会破坏我尝试在最里面的查询中应用的排序。在实践中,这没有发生,但我不能依赖它。

原始问题

我写了一个查询,当我进行假ROWNUM检查时,该查询似乎表现得更好:

  SELECT * FROM
  (
    SELECT DISTINCT * FROM 
    ( 
      SELECT TransactionID FROM WOWDev.QueryLog WHERE UPPER(UserName)=UPPER('xyz') AND TransactionID IS NOT NULL ORDER BY TransactionID DESC
    ) 
    WHERE ROWNUM<=1e100 -- fake ROWNUM check! this gets us on the fast path
  )
  WHERE ROWNUM<=50 

这是优化程序计划。

SELECT STATEMENT, GOAL = ALL_ROWS           38025   50  650
 COUNT STOPKEY                  
  VIEW  JSTILES     38025   801 10413
   SORT UNIQUE NOSORT           38025   801 3204
    COUNT STOPKEY                   
     VIEW   JSTILES     38024   801 3204
      TABLE ACCESS BY INDEX ROWID   WOWDEV  QUERYLOG    38024   545694  9276798
       INDEX FULL SCAN DESCENDING   WOWDEV  IX_QUERYLOG_TID 1263    212704  

如果我对假ROWNUM项检查发表评论,那么查询突然崩溃并变得慢得多(以及成本为5倍)。

SELECT STATEMENT, GOAL = ALL_ROWS           204497  50  650
 COUNT STOPKEY                  
  VIEW  JSTILES     204497  34865   453245
   SORT GROUP BY STOPKEY            204497  34865   592705
    INDEX FAST FULL SCAN    WOWDEV  IX_QUERYLOG_USER_TID    204462  545694  9276798

显然,这也是一个完全不同的指数(显然不适合它)。

如果我自然地简化查询并删除所有冗余,我们会得到类似的差版执行计划,同样性能也差。

SELECT * FROM 
(
  SELECT DISTINCT TransactionID
          FROM WOWDev.QueryLog
         WHERE UPPER(UserName) = UPPER('xyz')
           AND TransactionID IS NOT NULL
         ORDER BY TransactionID DESC
)
WHERE ROWNUM <= 50

解释如下:

SELECT STATEMENT, GOAL = ALL_ROWS           207527  50  650
 COUNT STOPKEY                  
  VIEW  JSTILES     207527  34865   453245
   SORT UNIQUE STOPKEY          207491  34865   592705
    INDEX FAST FULL SCAN    WOWDEV  IX_QUERYLOG_USER_TID    204462  545694  9276798

如下所述,我尝试将ROWNUM<=1e100替换为ROWNUM>0,这也是快速路径,但计划略有不同:

SELECT STATEMENT, GOAL = ALL_ROWS           38025   50  650
 COUNT STOPKEY                  
  VIEW  JSTILES     38025   801 10413
   SORT UNIQUE NOSORT           38025   801 3204
    COUNT                   
     FILTER                 
      VIEW  JSTILES     38024   801 3204
       TABLE ACCESS BY INDEX ROWID  WOWDEV  QUERYLOG    38024   545694  9276798
        INDEX FULL SCAN DESCENDING  WOWDEV  IX_QUERYLOG_TID 1263    212704  

任何人都可以解释这种行为吗?是否有更清洁,更少hacky的方式让Oracle走上快车道?

3 个答案:

答案 0 :(得分:2)

这不一定是正确答案,但......

我过去曾使用过ROWNUM > 0来强制实现&#39;数据。

这反过来允许查询处理器获得正确的基数。

例如,如果查询规划器认为特定谓词只返回一行,它通常会在其上使用笛卡尔连接。如果数据实际上不是一行而是很多,则笛卡尔连接会导致大量行和大量不正确的处理。添加ROWNUM > 0会强制它评估每行的rownum,然后才能评估ROWNUM&gt; 0,有效地强制实现数据的实现

看起来这实际上并不是你的问题。

也许是因为数据的传播,它实现得更快,然后搜索表而不是首先检查索引。

在该计划转储中是否有办法解决谓词的应用位置?

遗憾的是,你必须UPPER这个字段,因为它使它不具有可搜索性,并且不会在该字段上使用索引。

答案 1 :(得分:0)

我记得,在子查询中放置圆形谓词的一个影响是它可以防止谓词推送和某些类型的视图合并。

虽然它们通常都有利于查询性能,但在某些情况下它们会产生不良副作用。这曾经是一个可以用来代替优化器提示的技巧,以防止考虑转换。

答案 2 :(得分:-1)

您已经减少了添加&#34;假冒&#34; romwnum WHERE ROWNUM<=1e100

这指示数据库ROWNUM必须至多为1e100。

第一个查询更快的原因是外部选择需要处理一个小子集。

也许你可以更快地实现&#34;结果SELECT * FROM ( SELECT DISTINCT * FROM ( SELECT TransactionID FROM WOWDev.QueryLog WHERE UPPER(UserName)=UPPER('xyz') AND TransactionID IS NOT NULL ORDER BY TransactionID DESC ) WHERE ROWNUM<=50 -- move inside to get small result set )