rownum是什么?
rownum是一个伪列,在表中不是真实存在的
rownum是oracle从数据文件或者缓冲区读取数据的一个顺序
如果想得到一个表中第二行的数据,按照select * from test where rownum=1;这个查询,查询得到的数据不是正确的,而且只能是在=1时能查出数据,在等于其他值的时候是查不出任何数据的
rownum只能跟小于等于,不能跟大于,如果要大于需要和小于同时使用
rownum工作原理:
由于表中没有行号,因此是不能查询到第几行的数据的
首先,标准的 SQL 的解析顺序为:
(1).FROM 子句, 组装来自不同数据源的数据(2).WHERE 子句, 基于指定的条件对记录进行筛选(3).GROUP BY 子句, 将数据划分为多个分组(4).使用聚合函数进行计算(5).使用 HAVING 子句筛选分组(6).计算所有的表达式(7).使用 ORDER BY 对结果集进行排序(8).最后是select ,执行查询
rownum是在执行的查询语句执行谓词之后且在完成排序或者簇集之前赋予值的,在分配后值加1
既在有select 、from 、where 、group by 、having、order by 的查询中,先后执行顺序是:
from/where -> rownum(这个是从from/where结果中分配给每个行rownum并且增加1) -> select -> group by -> having -> order by
因为oracle会把执行查询的得到的第一个符合条件的结果rownum加1,而不符合条件的会仍掉,如果符合条件会在后面+1,而执行select * from test where rownum>1;而条件是>1,而1不是大于1的,就依次推全表扫表没有符合条件的值,所以这句话永远都查询不出来结果的!!!!
执行select * from test where rownum>1;这句话的执行计划:
SYS@u01>select * from test where rownum>1;no rows selectedElapsed: 00:00:00.08Execution Plan----------------------------------------------------------Plan hash value: 2091529335----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 69115 | 13M| 294 (1)| 00:00:04 || 1 | COUNT | | | | | ||* 2 | FILTER | | | | | || 3 | TABLE ACCESS FULL| TEST | 69115 | 13M| 294 (1)| 00:00:04 |----------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------2 - filter(ROWNUM>1)Note------ dynamic sampling used for this statement (level=2)Statistics----------------------------------------------------------49 recursive calls0 db block gets1267 consistent gets1363 physical reads0 redo size1343 bytes sent via SQL*Net to client512 bytes received via SQL*Net from client1 SQL*Net roundtrips to/from client4 sorts (memory)0 sorts (disk)0 rows processed
首先是TABLE ACCESS FULL.....
因为是先得到符合条件的行,再为符合条件的行对其赋予rownum ,在得到的行一次+1赋值,所以查出来的是1.2.3.....n.
例如对于emp表如果想知道薪水排在前5行的人的信息,执行:select * from emp where rownum<=5 order by sal desc;这样是不对的,这个是只是读取了5行然后再进行排序的,读取的这5行和之前插入的顺序有关
例如:
Select * From(Select a.*,Rownum rnum From(your_query_goes_here) aWhere Rownum <=:MAX_ROW_TO_FETCH)Where rnum>= :MIN:ROW_TO_FETCH;
与
Select * From(Select a.*,Rownum rnum From(your_query_goes_here) a)Where rnum between : MIN:ROW_TO_FETCH and <=:MAX_ROW_TO_FETCH;
这比较这两个执行语句,很显然第一个会比第二个执行速度快很多,扫描的数据不同
------------------------------------------------------------
rownum有Top-N的优化功能:使用rownum可以避免大数据集合的负载沉重的排序操作。
例如: Select * from (select * from big_emp order by salary) where ROWNUM<=N;
优化执行:首先oracle会对big_emp表做全表扫描,然后使用一个数组,这个数组里面有N个数据,也就是说紧把这N个数据缓存在内存中,紧对这N个数据排序。减少在内存中的缓存,这样会只对10个数据排序,扫描到一个排序增加一个,会大大减少时间!!!!
Top-N处理方法:
实例:
写一条SQL语句:
表中有1亿条记录,如何用一条sql取出user_name排倒序的后1000-1020条记录
SCOTT@u01>select rownum,rn FROM (Select rownum rn ,b.* from (select * from emp order by ename desc) b where rownum<10) where rn>5;ROWNUM RN---------- ----------1 62 73 84 9Elapsed: 00:00:00.01SCOTT@u01>
rn是已经排序后的,rownum是当前的
select rownum,rn FROM (Select rownum rn ,b.* from (select * from emp order by ename desc) b where rownum<10) where rn>5;
这个意思是:先根据 select * from emp order by ename desc按照ename倒序排序所有信息,然后再根据外面的 from/where 来根据排序后的结果筛选前10行,然后再根据最外面的from 在筛选后的10行数据的基础上再根据where条件选择rn>5的去掉前5行数据(这里使用的rn别名,是剩下10行的那个rownum,为了不与最外层的那个rownum冲突),然后得到的就是中间的排序后第5到10行数据
为了好理解,查询弄多个别名:
SCOTT@u01>select rownum,rn,re FROM (Select rownum rn ,b.* from (select rownum re,e.* from emp e order by ename desc) b where rownum<10) where rn>5;ROWNUM RN RE---------- ---------- ----------1 6 52 7 93 8 44 9 12Elapsed: 00:00:00.03SCOTT@u01>
set autot on;
既显示查询的结果,也显示执行计划、执行路径、统计信息
set autot trace
不显示查询的结果,只显示执行计划、执行路径、统计信息