我有一个SQL query,看起来是这样的:

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

从本质上讲,这是为了通过部分,是减缓下来的东西。如果我们要删除它,解释,成本下降,通过一个数量级(超过1000倍).我已经试过这样的:

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

但是,这并没有给出正确的结果。是否有任何简单的方法来加速这个吗?或者将我必须花费更多的时间用于解释工具?

有帮助吗?

解决方案

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's总是为了没有差距。

如果你使用 ROWNUM BETWEEN 10 and 20, 第一行,satisifies所有其他条件将成为一个候选人回返,临时分配 ROWNUM = 1 和失败的考验 ROWNUM BETWEEN 10 AND 20.

然后下一个行将一名候选人,与分配 ROWNUM = 1 和失败等等, 所以,最后,没有行将返回。

这应该是工作把 ROWNUM's入子查询。

其他提示

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

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

您需要通过某种方式订购这些分页查询是唯一的,因此每次都会确定地为行分配ROW_NUMBER。

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

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

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

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

索引也无法提供帮助。索引会给出订单,但充其量,它会让您在某个地方开始,然后继续阅读,直到您到达第567,900条。

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top