Oracle Paging:解析函数 ROW_NUMBER() VS ROWNUM
当网站需要进行分页时...哪种方法效果更好?
分析函数 - ROW_NUMBER()
- Oracle 10G
http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o17asktom-093877.html
选择列A, B栏 FROM (选择列A, B 栏, row_number() over (按 columnB 排序) rn 从表) LOW_LIMIT 和 OFFSET 之间的位置;
ROWNUM
- http: //www.oracle.com/technetwork/issue-archive/2007/07-jan/o56asktom-086197.html
INMHO 我发现这种方法是一种更易于人类阅读的代码
选择 * FROM ( SELECT rownum rn, a.* 从( 选择 A 列、B 列 从表 按 B 列排序 ) 一个 其中 rn <= 偏移量 ) WHERE rnum >= LOW_LIMIT
注意:我知道存在 RANK 和 DENSE_RANK 分析函数,但假设我只需要通过确定性查询进行分页。
注释 2:要检索记录总数,我正在考虑使用单独的简单查询 count(*)
When Paging needs to be done in an web site... Which method performs better?
Analytic function - ROW_NUMBER()
- Oracle 10G
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
- http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o56asktom-086197.html
INMHO I find this approach a more human-readable code
SELECT * FROM ( SELECT rownum rn, a.* FROM( SELECT columnA, columnB FROM table ORDER BY columnB ) a WHERE rn <= OFFSET ) WHERE rnum >= LOW_LIMIT
Note: I understand that there are RANK and DENSE_RANK analytic functions, but lets assume I just need page through deterministic queries.
Note 2: To retrieve the total amount of records I am thinking in using a separate simple query count(*)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我觉得这个问题很有趣,所以我尝试了一些东西。
我有一个名为 Large_t 的表,其中包含大约 110 万行。
然后我有两个查询:
如果
您查看两个查询生成的计划,第一个查询有一个操作:
虽然分析查询包含一个名为
SORT ORDER BY STOPKEY 的操作,但它是比普通 ORDER BY 更有效的排序操作。我不确定窗口排序推送排名是如何工作的,但它似乎以类似的方式工作。
运行两个查询后查看 v$sql_workarea,两个查询都只需要 4096 字节的 sort_area。
相反,如果我在没有分页查询的情况下运行查询:
那么所需的排序区域是 37M,证明两个查询中的排序大致相同。
通常,如果您想有效地返回排序查询的前 N 个,您将需要在排序列上建立索引 - 这将阻止 Oracle 完全需要排序。因此,我在 OBJECT_ID 上创建了一个索引,然后再次解释了这两个查询。
这次第一个查询使用了索引,并在 0.2 秒内返回,而第二个查询没有使用新索引,速度慢得多。
因此,我从快速分析中得出的结论是,在一般情况下,使用 rownum 进行过滤或分析 row_number 函数的执行效果大致相同。但是,rownum 示例自动开始使用我在表上创建的索引,而 row_number 没有。也许我可以让它使用带有一些提示的索引——这是你可以尝试的其他东西。
I thought this question was interesting, so I tried a few things out.
I have table called large_t, that contains about 1.1M rows.
Then I have two queries:
And
If you look at the plans the two queries generate, the first has an operation:
While the analytic query contains an operation called
The SORT ORDER BY STOPKEY is a more efficient sort operation that a plain ORDER BY. I am not sure how a WINDOW SORT PUSHED RANK works, but it seems to work in a similar fashion.
Looking at v$sql_workarea after running both queries, both only required a sort_area of 4096 bytes.
In contrast, if I ran the query without a paging query:
Then the sort area required is 37M, proving the sort in both queries is about the same.
Normally, if you want to efficiently return the TOP N of a sorted query, you will want an index on the sorting column - that will prevent Oracle needing to sort at all. So, I created an index on OBJECT_ID, and then explained both queries again.
This time the first query used the index and returned in 0.2 seconds, while the second query didn't use the new index and was much slower.
So my conclusion from this quick bit of analysis is that in the general case using rownum to filter or the analytic row_number function both perform about the same. However, the rownum example automatically started using the index I created on the table when row_number did not. Maybe I could get it to use the index with some hints - that is something else you can experiment with.
除了答案中提到的其他差异之外,您还应该考虑性能。这里有一篇非权威但很有趣的报告,比较了各种分页方式,其中
ROWNUM
的使用与ROW_NUMBER() OVER()
相比:https://web.archive.org/web/20160901191310/http://www.inf.unideb.hu:80/~gabora/pagination/results.html
Apart from the other differences mentioned in answers, you should also consider performance. There is a non-authoritative but very interesting report here, comparing various means of pagination, among which the use of
ROWNUM
compared toROW_NUMBER() OVER()
:https://web.archive.org/web/20160901191310/http://www.inf.unideb.hu:80/~gabora/pagination/results.html
生成您自己的经验结果:
当然,您可以增加表的大小以满足您的测试目的!
设置计时并针对大表运行两个查询。
更改表结构以更好地适合您的测试,因为您可能也希望为查询对某些列建立索引等。但本质上这是一个简单的测试,不会花费您很长时间来运行。
如果两者的时间大致相同,则使用最具可读性(因此最受支持)的版本。
To generate your own empirical results:
Of course, you can increase the size of the table to suit your testing purposes!
Set timing on and run both queries against the large table.
Change the table structure to better suit your test as you may want some columns to be indexed for your query too etc. but essentially it is a simple test and won't take you long to run.
If both come out roughly the same timings then use the most readable (and hence supportable) version.