oracle中row_number和rownum的区别和联系(翻译)
http://www.tuicool.com/articles/bI3IBv
附问题:有以下一个SQL语句:
SELECT *
FROM (
SELECT t.*, row_number() OVER (ORDER BY ID) rn
FROM mytable t
)
WHERE rn BETWEEN :start and :end
sql中的order by语句大大降低了处理的速度,如果把order by去掉,相应的执行计划会大大地提高。如果换成下面的sql:
SELECT t.*, row_number() OVER (ORDER BY ID) rn
FROM mytable t
WHERE rownum BETWEEN :start and :end
很明显,这个sql是错的,根本查询不了正确的数据信息。是否有其它的方法可以提高查询速度?
针对以上问题,就必须要了解一下关于row_number和rownum的区别,以及如何来运用这些信息。
首先了解一下rownum是如何进行工作的,根据oracle的官方文档:
如果对rownum进行大于比较,这个比较将直接返回false。如,下列sql语句将不能返回任何数据信息:
SELECT *
FROM employees
WHERE ROWNUM > 1
在查询中,第一条被命中的数据将赋予一个伪列rownum为1,那么这个条件就为false。第二条被命中的数据由于第一条的false将重新成为第一条数据,那么仍然赋值为1,显示这个条件仍然为false。后续所有的数据将重复执行这个逻辑,最后一条数据也没有返回。
这就是为什么之前的第2个查询,应该转换为以下的sql语句:
SELECT *
FROM (
SELECT t.*, ROWNUM AS rn
FROM mytable t
ORDER BY
paginator, id
)
WHERE rn BETWEEN :start and :end
接下来,需要通过创建一些临时数据表来查看这个sql语句的执行性能,我们将创建临时表,追加索引,然后填充数据,最后分析这个sql语句的查询信息。
CREATE TABLE mytable (
id NUMBER(10) NOT NULL,
paginator NUMBER(10) NOT NULL,
value VARCHAR2(50)
)
/
ALTER TABLE mytable
ADD CONSTRAINT pk_mytable_id PRIMARY KEY (id)
/ CREATE INDEX ix_mytable_paginator_id ON mytable(paginator, id)
/ INSERT
INTO mytable(id, paginator, value)
SELECT level, level / 10000, 'Value ' || level
FROM dual
CONNECT BY
level <= 1000000
/ COMMIT
/ BEGIN
DBMS_STATS.gather_schema_stats('"20090506_rownum"');
END;
/
这个Sql语句创建一个包括100万条数据的表,并且创建一个联合索引.
同时,在这个查询中,patinator字段是不是惟一的,是为了在之后展示这样一种现象:
在查询中,某些数据可能在不同的分页查询中出现多次,而某些数据则可能根据不会被查询出
这就是所谓的分页混乱。
然后,分别使用row_numer和rownum分别进行查询,返回从900001到900010之间的10条数据信息。
row_number()
SELECT *
FROM (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY paginator, id) AS rn
FROM mytable t
)
WHERE rn BETWEEN 900001 AND 900010
| ID | PAGINATOR | VALUE | RN | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 900001 | 90 | Value 900001 | 900001 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900002 | 90 | Value 900002 | 900002 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900003 | 90 | Value 900003 | 900003 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900004 | 90 | Value 900004 | 900004 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900005 | 90 | Value 900005 | 900005 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900006 | 90 | Value 900006 | 900006 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900007 | 90 | Value 900007 | 900007 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900008 | 90 | Value 900008 | 900008 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900009 | 90 | Value 900009 | 900009 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900010 | 90 | Value 900010 | 900010 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10 rows fetched in 0.0005s (0.8594s) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SELECT STATEMENT
VIEW
WINDOW NOSORT STOPKEY
TABLE ACCESS BY INDEX ROWID, 20090506_rownum.MYTABLE
INDEX FULL SCAN, 20090506_rownum.IX_MYTABLE_PAGINATOR_ID
rownum
SELECT *
FROM (
SELECT t.*, ROWNUM AS rn
FROM (
SELECT *
FROM mytable
ORDER BY
paginator, id
) t
)
WHERE rn BETWEEN 900001 AND 900010
| ID | PAGINATOR | VALUE | RN | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 900001 | 90 | Value 900001 | 900001 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900002 | 90 | Value 900002 | 900002 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900003 | 90 | Value 900003 | 900003 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900004 | 90 | Value 900004 | 900004 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900005 | 90 | Value 900005 | 900005 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900006 | 90 | Value 900006 | 900006 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900007 | 90 | Value 900007 | 900007 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900008 | 90 | Value 900008 | 900008 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900009 | 90 | Value 900009 | 900009 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900010 | 90 | Value 900010 | 900010 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10 rows fetched in 0.0005s (0.7058) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SELECT STATEMENT
VIEW
COUNT
VIEW
TABLE ACCESS BY INDEX ROWID, 20090506_rownum.MYTABLE
INDEX FULL SCAN, 20090506_rownum.IX_MYTABLE_PAGINATOR_ID
从上文中,可以看出,使用rownum的查询速度略快于row_number函数。
然后再看一个row_number查询,可以看出oracle足够的智能,它可以通过使用联合索引而避免进行排序操作,然后通过使用stopkey操作,可以直接快速查找到相应的数据信息。
rownum查询也同样使用索引,但并没有利用stopkey条件,只是简单的计数操作。
那
么,能否同样让rownum使用stopkey呢。在之前的查询中,oracle并不知道这个rn就是在内层查询rownum的别名,我们可以重写查询,
在外层查询中使用rownum,这样就可以在外层利用stopkey条件了。这就是我们常见的oracle3层分页的变形:
SELECT *
FROM (
SELECT t.*, ROWNUM AS rn
FROM (
SELECT *
FROM mytable
ORDER BY
paginator, id
) t
)
WHERE rn >= 900001
AND rownum <= 10
| ID | PAGINATOR | VALUE | RN | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 900001 | 90 | Value 900001 | 900001 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900002 | 90 | Value 900002 | 900002 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900003 | 90 | Value 900003 | 900003 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900004 | 90 | Value 900004 | 900004 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900005 | 90 | Value 900005 | 900005 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900006 | 90 | Value 900006 | 900006 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900007 | 90 | Value 900007 | 900007 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900008 | 90 | Value 900008 | 900008 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900009 | 90 | Value 900009 | 900009 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 900010 | 90 | Value 900010 | 900010 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10 rows fetched in 0.0005s (0.4714s) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SELECT STATEMENT
COUNT STOPKEY
VIEW
COUNT
VIEW
TABLE ACCESS BY INDEX ROWID, 20090506_rownum.MYTABLE
INDEX FULL SCAN, 20090506_rownum.IX_MYTABLE_PAGINATOR_ID
在这个查询中,oracle利用了stopkey,同时速度只有471ms,比原来更快。
如果row_number和rownum使用同样的执行计划,但为什么rownum明显更快呢。
这是因为:oracle的历史实在是太久了,而不同的时间导致相同的特性却有不同的效果。
rownum在oracle6中被引进,发布时间为1988年,在当时什么资源和条件都不满足的情况下,作为一个简单的计数器,被认为是非常简单和高效的。
而随着时代的发展,更多的需求被提及出来,这时,一个相当于但功能比rownum更强大的函数被引入,这就是row_number函数,它从oracle9i开始被引进。这时,效率已经不再是惟一的条件了,所以row_number的实现也不再以效率为惟一的指标了。
当然,如果你有更多的要求,如分组排序等,则需要使用row_number函数,但如果你仅仅是简单的分页查询,建议使用
rownum,这也是为什么在现在的时代rownum还是这么流行(据说在oracle12c中有offset分页操作符了,内部同样使用
row_number函数,这样rownum可以退休了)
以下是英文原文:http://explainextended.com/2009/05/06/oracle-row_number-vs-rownum/
oracle中row_number和rownum的区别和联系(翻译)的更多相关文章
- oracle的row_number()和rownum
row_number() 函数和rownum的介绍: 1.row_number() 方法的格式: row_number()over([partition by col1] order by col2) ...
- oracle中函数和存储过程的区别和联系【转载竹沥半夏】
oracle中函数和存储过程的区别和联系[转载竹沥半夏] 在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,但也有自己的特点.刚学完函数和存储过程,下面来和大家分享一下自己 ...
- oracle中函数和存储过程的区别和联系
oracle中函数和存储过程的区别和联系 在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,但也有自己的特点.刚学完函数和存储过程,下面来和大家分享一下自己总结的关于函数和 ...
- oracle中row_number() over()分析函数用法
row_number()over(partition by col1 order by col2)表示根据col1分组,在分组内部根据col2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内 ...
- Oracle中的rowid rownum
1. rowid和rownum都是虚列 2. rowid是物理地址,用于定位oracle中具体数据的物理存储位置 3. rownum则是sql的输出结果排序,从下面的例子可以看出其中的区别. rowi ...
- (转)ORACLE中SID和SERVICE_NAME的区别
背景:之前一直分不清plsql和程序中配置文件url之间的连接,想当然的认为service_name 和jdburl后面的实例相对应,直到出错的这一天,通过这篇博客,彻底扫除了盲点. 1 问题 1.1 ...
- 转://Oracle中User和Schema的区别和联系
今天在阅读Oracle官方文档的时候,读到schema的基本概念,这就让我产生了一个疑问:user和schema两者之间到底有什么区别?为了更深层次的理解二者之间的区别和联系,以下是官方文档中关于us ...
- Oracle中Restore和Recovery的区别
一.参考解释一 在Oracle的备份与恢复的知识点中,经常会出现Restore 和 Recovery两个词. 由于这两个词在字典中的解释很接近,困扰了我很久.直到我在Oracle的官方文档中看到了以下 ...
- Oracle中用户和方案的区别
从定义中我们可以看出方案(Schema)为数据库对象的集合,为了区分各个集合,我们需要给这个集合起个名字,这些名字就是我们在企业管理器的方案下看到的许多类似用户名的节点,这些类似用户名的节点其实就是一 ...
随机推荐
- mfc对话询问窗体
// 显示消息对话框 nRes = MessageBox(_T("您确定要跳转网站?"), _T("提示"), MB_OKCANCEL | MB_I ...
- python 2.7 学习笔记--文件的基本操作
1.打开文件的方式 file_obj = file("文件路径","模式") file_obj = open("文件路径","模式 ...
- Kali 开机报错解决方案
问题一: piix4_smbus ::007.3: Host SMBus controller not enabled 解决:打开 /etc/modprobe.d/blacklist.conf 末尾加 ...
- 基于SS5服务端的Socks5客户端
SS5停止更新已经好几年了,用作socks5代理的服务端还是比较稳定的.但是如果要使用加密账号和密码的协议,有些坑需要去填. 1.服务端的账号密码验证方式配置为“s”时,客户端进行协议验证时,需要用“ ...
- python3的pickle导致乱码
资料: http://www.cnblogs.com/pzxbc/archive/2012/03/18/2404715.html http://bbs.chinaunix.net/thread-419 ...
- SQL中NULL值
SQL的表达式,除了IS NULL和NOT NULL以外,只要出现NULL值结果都为FALSE 简单的例子: SELECT * FROM table WHERE name!='abc' 只要name值 ...
- [转]jquery mobile中redirect重定向问题
本文转自:http://www.cnblogs.com/freeliver54/p/3529813.html 在jquerymobile提交后如果要进行网页重定向时,一定要在form或<a> ...
- 类js效果
类似js效果,点击看看 代码 onclick="return confirm('您确定要看看吗?')" 放入a标签里面
- Eclipse 一些小知识
快速查找未完成事项 eg: // TODO 通过模板格式化代码 Window --> Preferences --> Java --> Editor --> Template ...
- 让textarea完全显示文章并且不滚动、不可拖拽、不可编辑
textarea { width: 100%; border: none; outline: none; resize: none; overflow: hidden; padding-bottom: ...