2011-08-16 26 views
1

当需要在网站中完成寻呼...哪种方法执行得更好?解析函数ROW_NUMBER()VS ROWNUMBER - Oracle Paging

解析功能 - ROW_NUMBER()

ROWNUMBER

  • http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o56asktom-086197.html
  • INMHO我发现这种方法更可读的代码

    SELECT * FROM (
        SELECT rownum rn, a.* 
        FROM(
        SELECT columnA, columnB 
        FROM table 
        ORDER BY columnB 
    ) a 
        WHERE rn <= OFFSET 
    ) 
    WHERE rnum >= LOW_LIMIT 
    
    • 注:据我所知,有RANK和DENSE_RANK解析函数,但是让我们假设我只需要网页通过确定性查询。

    • 注2:要检索的记录,我在使用一个单独的简单查询COUNT(*)

+0

多少行,你处理?你有没有检查解释计划? – Chandu

+1

可能的重复[如何加快Oracle中的row_number?](http://stackoverflow.com/questions/827108/how-can-i-speed-up-row-number-in-oracle) –

+1

尝试加载一个测试表中包含大量数据并对它们进行测试,瞧,你的答案直接针对你正在运行的硬件/网络/环境定制(由于你自己进行测试的结果)。 – Ollie

回答

7

我以为这个问题很有趣,所以我尝试了几件事。

我有一个名为large_t的表,它包含大约1.1M行。

然后我有两个疑问:

select * 
from 
(
    select rownum rnum, a.* 
    from (
     select owner, object_name, object_id 
     from large_t 
     order by object_id 
     ) a 
    where rownum <= 30  
) where rnum > 20; 

而且

select * 
from 
(
select owner, object_name, object_id, 
     row_number() over (order by object_id) rnum 
from large_t 
) where rnum > 20 and rnum <= 30; 

如果你看看这两个查询产生的计划,首先有一个操作:

SORT ORDER BY STOPKEY 

虽然分析查询包含名为

的操作
WINDOW SORT PUSHED RANK 

通过STOPKEY排序是一种更高效的排序操作,它是一个普通的ORDER BY。我不确定WINDOW SORT PUSHED RANK是如何工作的,但它似乎以类似的方式工作。

运行这两个查询后查看v $ sql_workarea,两者都只需要一个4096字节的sort_area。

相反,如果我跑了查询无分页查询:

select owner, object_name, object_id 
from large_t 
order by object_id 

然后需要排序区为37M,证明在这两个查询排序是差不多的。

通常情况下,如果要高效地返回排序查询的TOP N,您需要在排序列上使用索引 - 这将防止Oracle需要进行排序。所以,我在OBJECT_ID上创建了一个索引,然后再次解释了这两个查询。

这次第一个查询使用索引并在0.2秒内返回,而第二个查询没有使用新索引,速度也慢得多。

所以我从这个快速分析的结论是,在一般情况下,使用rownum过滤或分析row_number函数都执行大致相同。但是,当row_number没有时,rownum示例自动使用我在表上创建的索引开始。也许我可以通过一些提示使用索引 - 这是你可以尝试的其他东西。

0

要生成自己的实证结果想总量:

-- Create test table 
CREATE TABLE test_large_tab (
    tlt_id NUMBER, 
    tlt_data VARCHAR2(50) 
); 

-- Load with data 
BEGIN 
    FORALL i IN 1 .. 1000000 
     INSERT INTO test_large_tab 
     (
     tlt_id, 
     tlt_data 
    ) 
     VALUES 
     (
     i, 
     TO_CHAR(sysdate-i, 'FMMon ddth, YYYY') 
    ); 
END; 

当然,您可以增加表格的大小以适合您的测试目的!

设置计时并针对大型表运行这两个查询。

更改表结构以更好地适合您的测试,因为您可能希望将某些列索引为您的查询等等,但本质上这是一个简单的测试,不会花费您很长时间才能运行。

如果两者出现大致相同的时间,则使用最易读(因此可支持)的版本。

+0

我会自己做一个测试,但我没有权限在数据库创建表。顺便说一句,我发现了一篇关于如何创建虚拟表/记录的伟大文章。 [link](http://blog.lishman.com/2008/02/how-to-generate-rows-in-oracle_2477.html) – Jimmy