当需要在网站上进行分页时...哪种方法表现更好?
分析功能 - ROW_NUMBER()
http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o17asktom-093877.html
SELECT columnA,
columnB
FROM (SELECT columnA,
columnB,
row_number() over (order by columnB) rn
FROM table)
WHERE rn BETWEEN LOW_LIMIT AND OFFSET;
ROWNUM
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:使用单独的简单查询计数检索我正在考虑的记录总数(*)
答案 0 :(得分: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
SORT ORDER BY 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示例使用我在表上创建的索引自动启动。也许我可以通过一些提示来使用索引 - 这是你可以尝试的其他东西。
答案 1 :(得分:4)
除了答案中提到的其他差异外,您还应该考虑表现。这里有一个非权威但非常有趣的报告,比较各种分页方式,其中使用ROWNUM
与ROW_NUMBER() OVER()
进行比较:
答案 2 :(得分: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;
当然,您可以增加表格的大小以适合您的测试目的!
设置计时并对大表运行两个查询。
更改表格结构以更好地适合您的测试,因为您可能希望为查询索引某些列等等,但实质上它只是一个简单的测试,并且不会花费很长时间来运行。
如果两者的时间大致相同,那么使用最易读(也就是可支持的)版本。