如何加速Oracle中的row_number?

时间:2009-05-05 21:59:22

标签: sql oracle oracle10g row-number

我的SQL查询看起来像这样:

SELECT * FROM(
    SELECT
        ...,
        row_number() OVER(ORDER BY ID) rn
    FROM
        ...
) WHERE rn between :start and :end

基本上,正是ORDER BY部分减慢了速度。如果我要删除它,EXPLAIN成本会下降一个数量级(超过1000倍)。我试过这个:

SELECT 
    ...
FROM
    ...
WHERE
    rownum between :start and :end

但这并没有给出正确的结果。有没有简单的方法来加快速度?或者我是否需要花更多时间使用EXPLAIN工具?

5 个答案:

答案 0 :(得分:13)

ROW_NUMBER中,

Oracle效率很低。

请参阅我博客中的文章了解效果详情:

对于您的特定查询,我建议您将其替换为ROWNUM,并确保使用该索引:

SELECT  *
FROM    (
        SELECT  /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
                t.*, ROWNUM AS rn
        FROM    table t
        ORDER BY
                column
        )
WHERE rn >= :start
      AND rownum <= :end - :start + 1

此查询将使用COUNT STOPKEY

另外,要么确保column不可为空,要么添加WHERE column IS NOT NULL条件。

否则索引不能用于检索所有值。

请注意,如果没有子查询,则无法使用ROWNUM BETWEEN :start and :end

ROWNUM总是最后分配并最后检查,ROWNUM总是按顺序排列。

如果您使用ROWNUM BETWEEN 10 and 20,则满足所有其他条件的第一行将成为返回的候选者,暂时分配ROWNUM = 1并且未通过ROWNUM BETWEEN 10 AND 20的测试。

然后下一行将是候选人,分配ROWNUM = 1并失败等等,所以,最后,根本不会返回任何行。

这应该通过将ROWNUM放入子查询中来解决。

答案 1 :(得分:5)

看起来像是一个分页查询。

从这篇ASKTOM文章(约90%页面):

You need to order by something unique for these pagination queries, so that ROW_NUMBER is assigned deterministically to the rows each and every time.

此外,您的查询不在同一个地方,因此我不确定比较其中一个的成本有什么好处。

答案 2 :(得分:1)

您的ORDER BY列是否已编入索引?如果不是那个开始的好地方。

答案 3 :(得分:1)

问题的一部分是“开始”到“结束”跨度有多大以及它们“存在”的位置。 假设你在表中有一百万行,并且你想要行567,890到567,900那么你将不得不忍受这样一个事实:它需要通过整个表,通过id排序几乎所有这些,并确定哪些行属于该范围。

简而言之,这是很多工作,这就是为什么优化器会给它带来高成本的原因。

索引也无法提供帮助。一个索引会给出订单,但充其量,这会让你有一个开始的地方,然后你继续阅读,直到你到达567,900条目。

如果您一次向最终用户显示10个项目,则可能值得从数据库中获取前100名,然后让应用程序将该100个项目分成10个块。

答案 4 :(得分:0)

花更多时间使用EXPLAIN PLAN工具。如果您看到TABLE SCAN,则需要更改查询。

您的查询对我来说毫无意义。查询ROWID似乎在寻找麻烦。该查询中没有关系信息。这是您遇到问题的真实查询,还是您用来说明问题的示例?