oracle rownum的理解
2011-10-24 16:35
369 查看
一、Rownum的描述:
rownum是一个伪列,数据库中并不保存rownum的列值,它是oracle系统为返回的结果集顺序分配的行编号,rownum是随着结果集生成的,一旦生成,在同一个结果集中就不会变化了,rownum值是依次递加的(从1开始),没有1就永远不会有2。
当某一行记录读入内存时,相应的ROWNUM才被动态地赋值。
二、Rownum运行机制:
1 Oracle executes your query.
2 Oracle fetches the first row and calls it row number 1.
3 Have we gotten past row number meets the criteria? If no, then Oracle discards the row, If yes, then Oracle return the row.
4 Oracle fetches the next row and advances the row number (to 2, and then to 3, and then to 4, and so forth).
5 Go to step 3.
三、Rownum的使用:
a)特殊结果的输出:
1.Top N结果输出:
2.分页查询(目前比较高效的分页方式):
3.分组子排序:
比如对上面结果集,根据EAPRCHY_CODE分组,再进行小组内排序:
四、使用陷阱:
(1)排序的陷阱(针对排序字段非主键的情况):
对上面结果集排序取PURCHASE_PRICE最低的3条记录,如果这样写sql会得出如下结果:
因为sql处理时rownum是先赋值的,所以会先取出前3条数据,然后再进行排序,而我们要的是排序后的价格最低的3条数据,应该这样:
(2)排序的陷阱(针对排序字段为主键的情况):
对于排序字段为主键这种情况,也要分两种情况 :(下面例子测试根据主键terminal_id进行排序:表tf_r_terminal_arch,主键terminal_id,terminal_state上建有索引IDX_TF_R_MOBILEDEVICE_STATE)
1.where 条件中有索引字段条件:这种情况下会先走该字段进行索引查询,rownum赋值,最后根据主键排序:
从上面执行计划可以看出查询是先提取Top N进行rownum赋值(COUNT STOPKEY),后进行主键排序(SORT ORDER BY),其实这种情况和非主键排序是一样的,应该这样处理:
上面就是先进行SORT ORDER BY STOPKEY (这一步就可以得到根据主键terminal_id排序的7条记录集),然后转化成view视图,COUNT STOPKEY根据rownum取出前3条记录。
2.where条件中无索引字段条件:这种情况下会根据主键索引进行查询,先排序,后rownum赋值。
说明:
执行计划中的COUNT STOPKEY 机制是只针对rownum而设定的,专门是为了提取top n 的需求优化的
SORT ORDER BY STOPKEY操作是Oracle处理rownum+orderby的一种优化算法。这个操作本质上很像算法中的快排序。首先是将数据集合分成两个部分(A和B),保证A中排序值都不小于B中排序值。在对A集合分割成两部分,依次进行。数据集B和其他那些小数据集合就不进行排序了。这样操作,只进行较少的排序次数,就可以最快的获取全局最大(或者最小)的几个数据。
以上是自己的一个理解情况,可能有不对的地方,希望大家一起指点讨论。
rownum是一个伪列,数据库中并不保存rownum的列值,它是oracle系统为返回的结果集顺序分配的行编号,rownum是随着结果集生成的,一旦生成,在同一个结果集中就不会变化了,rownum值是依次递加的(从1开始),没有1就永远不会有2。
当某一行记录读入内存时,相应的ROWNUM才被动态地赋值。
二、Rownum运行机制:
1 Oracle executes your query.
2 Oracle fetches the first row and calls it row number 1.
3 Have we gotten past row number meets the criteria? If no, then Oracle discards the row, If yes, then Oracle return the row.
4 Oracle fetches the next row and advances the row number (to 2, and then to 3, and then to 4, and so forth).
5 Go to step 3.
三、Rownum的使用:
a)特殊结果的输出:
1.Top N结果输出:
SQL> select t.terminal_id,t.time_in,ROWNUM from tf_r_terminal_arch t WHERE t.terminal_state='0' AND ROWNUM <5; TERMINAL_ID TIME_IN ROWNUM ------------------------------ ----------- ---------- 700000003840655 2011/8/17 1 700000003840660 2011/7/28 2 700000003840659 2011/7/28 3 700000003840656 2011/7/28 4
2.分页查询(目前比较高效的分页方式):
SQL> SELECT a.* FROM (select t.terminal_id,t.eparchy_code,ROWNUM rn from tf_r_terminal_arch t WHERE t.terminal_state='0' 2 AND ROWNUM <=7) a WHERE a.rn>=3 ; TERMINAL_ID EPARCHY_CODE RN ------------------------------ ------------ ---------- 700000003840659 0898 3 700000003840656 0898 4 700000003840653 0898 5 700000003840661 0899 6 700000003840658 0899 7
3.分组子排序:
SQL> select t.terminal_id,t.eparchy_code,ROWNUM from tf_r_terminal_arch t WHERE t.terminal_state='0'; TERMINAL_ID EPARCHY_CODE ROWNUM ------------------------------ ------------ ---------- 700000003840655 0897 1 700000003840660 0897 2 700000003840659 0898 3 700000003840656 0898 4 700000003840653 0898 5 700000003840661 0899 6 700000003840658 0899 7
比如对上面结果集,根据EAPRCHY_CODE分组,再进行小组内排序:
SQL> SELECT b.terminal_id, decode(ROWNUM - min_rn,0,c.eparchy_code,NULL) eparchy_code, ROWNUM - min_rn + 1 NO 2 FROM (select t.terminal_id,t.eparchy_code from tf_r_terminal_arch t WHERE t.terminal_state='0') b, 3 (SELECT eparchy_code, MIN(rn) min_rn FROM 4 (select t.terminal_id,t.eparchy_code,ROWNUM rn from tf_r_terminal_arch t WHERE t.terminal_state='0') a 5 GROUP BY a.eparchy_code) c WHERE b.eparchy_code = c.eparchy_code 6 ; TERMINAL_ID EPARCHY_CODE NO ------------------------------ ------------ ---------- 700000003840655 0897 1 700000003840660 2 700000003840659 0898 1 700000003840656 2 700000003840653 3 700000003840661 0899 1 700000003840658 2
四、使用陷阱:
(1)排序的陷阱(针对排序字段非主键的情况):
SQL> select t.terminal_id, t.purchase_price from tf_r_terminal_arch t WHERE t.terminal_state='0'; TERMINAL_ID PURCHASE_PRICE ------------------------------ -------------- 700000003840655 1980 700000003840660 1380 700000003840659 1680 700000003840656 1480 700000003840653 3300 700000003840661 2380 700000003840658 1590
对上面结果集排序取PURCHASE_PRICE最低的3条记录,如果这样写sql会得出如下结果:
SQL> select t.terminal_id, t.purchase_price from tf_r_terminal_arch t WHERE t.terminal_state='0' AND ROWNUM<=3 2 ORDER BY t.purchase_price 3 ; TERMINAL_ID PURCHASE_PRICE ------------------------------ -------------- 700000003840660 1380 700000003840659 1680 700000003840655 1980
因为sql处理时rownum是先赋值的,所以会先取出前3条数据,然后再进行排序,而我们要的是排序后的价格最低的3条数据,应该这样:
SQL> SELECT * FROM ( 2 select t.terminal_id, t.purchase_price from tf_r_terminal_arch t WHERE t.terminal_state='0' 3 ORDER BY t.purchase_price ) a WHERE ROWNUM <=3 4 ; TERMINAL_ID PURCHASE_PRICE ------------------------------ -------------- 700000003840660 1380 700000003840656 1480 700000003840658 1590
(2)排序的陷阱(针对排序字段为主键的情况):
对于排序字段为主键这种情况,也要分两种情况 :(下面例子测试根据主键terminal_id进行排序:表tf_r_terminal_arch,主键terminal_id,terminal_state上建有索引IDX_TF_R_MOBILEDEVICE_STATE)
1.where 条件中有索引字段条件:这种情况下会先走该字段进行索引查询,rownum赋值,最后根据主键排序:
SQL> select t.terminal_id, t.purchase_price from tf_r_terminal_arch t WHERE t.terminal_state='0' AND ROWNUM <=3 2 ORDER BY t.terminal_id; TERMINAL_ID PURCHASE_PRICE ------------------------------ -------------- 700000003840655 1980 700000003840659 1680 700000003840660 1380 SQL> explain plan for select t.terminal_id, t.purchase_price from tf_r_terminal_arch t WHERE t.terminal_state='0' AND ROWNUM <=3 2 ORDER BY t.terminal_id; Explained SQL> select plan_table_output from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 3199904717 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | By -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 3 | | 1 | SORT ORDER BY | | 3 | |* 2 | COUNT STOPKEY | | | | 3 | TABLE ACCESS BY INDEX ROWID| TF_R_TERMINAL_ARCH | 7 | |* 4 | INDEX RANGE SCAN | IDX_TF_R_MOBILEDEVICE_STATE | 7 | -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter(ROWNUM<=3) 4 - access("T"."TERMINAL_STATE"='0') 17 rows selected
从上面执行计划可以看出查询是先提取Top N进行rownum赋值(COUNT STOPKEY),后进行主键排序(SORT ORDER BY),其实这种情况和非主键排序是一样的,应该这样处理:
SQL> SELECT * FROM ( 2 select t.terminal_id, t.purchase_price from tf_r_terminal_arch t WHERE t.terminal_state='0' 3 ORDER BY t.terminal_id ) a WHERE ROWNUM <=3; TERMINAL_ID PURCHASE_PRICE ------------------------------ -------------- 700000003840653 3300 700000003840655 1980 700000003840656 1480 SQL> select plan_table_output from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 2297731398 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | B -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 3 | |* 1 | COUNT STOPKEY | | | | 2 | VIEW | | 7 | |* 3 | SORT ORDER BY STOPKEY | | 7 | | 4 | TABLE ACCESS BY INDEX ROWID| TF_R_TERMINAL_ARCH | 7 | |* 5 | INDEX RANGE SCAN | IDX_TF_R_MOBILEDEVICE_STATE | 7 | -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<=3) 3 - filter(ROWNUM<=3) 5 - access("T"."TERMINAL_STATE"='0') 19 rows selected
上面就是先进行SORT ORDER BY STOPKEY (这一步就可以得到根据主键terminal_id排序的7条记录集),然后转化成view视图,COUNT STOPKEY根据rownum取出前3条记录。
2.where条件中无索引字段条件:这种情况下会根据主键索引进行查询,先排序,后rownum赋值。
SQL> explain plan for 2 2 select t.terminal_id, t.purchase_price from tf_r_terminal_arch t WHERE t.terminal_type_code='01' AND ROWNUM <=3 3 ORDER BY t.terminal_id 4 ; Explained SQL> select plan_table_output from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 1588539088 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | C -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 3 | 63 | |* 1 | COUNT STOPKEY | | | | |* 2 | TABLE ACCESS BY INDEX ROWID| TF_R_TERMINAL_ARCH | 2500 | 52500 | | 3 | INDEX FULL SCAN | PK_TF_R_TERMINAL_ARCH | 13 | | -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<=3) 2 - filter("T"."TERMINAL_TYPE_CODE"='01') 16 rows selected
说明:
执行计划中的COUNT STOPKEY 机制是只针对rownum而设定的,专门是为了提取top n 的需求优化的
SORT ORDER BY STOPKEY操作是Oracle处理rownum+orderby的一种优化算法。这个操作本质上很像算法中的快排序。首先是将数据集合分成两个部分(A和B),保证A中排序值都不小于B中排序值。在对A集合分割成两部分,依次进行。数据集B和其他那些小数据集合就不进行排序了。这样操作,只进行较少的排序次数,就可以最快的获取全局最大(或者最小)的几个数据。
以上是自己的一个理解情况,可能有不对的地方,希望大家一起指点讨论。
相关文章推荐
- Oracle rownum的理解以及rownum分组出现重复数据的解决方法
- oracle-rownum的理解
- Oracle之rownum理解与分页查询的
- 对oracle伪列rownum产生机制的理解
- oracle 分页(rownum的理解) 以及 树节点的查询
- oracle中rownum的理解
- oracle ebs 理解Oracle企业架构模型
- Oracle的rownum
- ygfmobileORACLE中用rownum分页并排序的SQL语句
- [转载]Oracle的rownum原理和使用
- Oracle null的理解(转)
- oracle_SQL中ROWID与ROWNUM的使用
- Oracle 高效分页技术 根据ROWNUM分页
- Oracle中的等待事件是什么?如何理解并优化Oracle
- 全面解析oracle rownum
- Oracle里rownum的用法
- oracle理解
- ROWNUM-Oracle中的分页代码
- oracle数据类型----rownum
- ORACLE时间函数(SYSDATE)深入理解