问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

oracle分页问题,rownum<?这个条件可以提前吗?

发布网友 发布时间:2022-04-09 15:29

我来回答

2个回答

懂视网 时间:2022-04-09 19:50

SELECT COUNT(*) FROM BPM_PROCVAR; COUNT(*) ---------- 2121400

 

1、分页写法一

SELECT *
 FROM (SELECT ROWNUM RN, A.*
  FROM (SELECT * FROM BPM_PROCVAR ORDER BY VARID) A
  WHERE ROWNUM <= 40) B
 WHERE B.RN >= 21;

查询结果:20条记录,查询时间:0.031秒

2、分页写法二

SELECT *
 FROM (SELECT ROWNUM RN, A.*
  FROM (SELECT * FROM BPM_PROCVAR ORDER BY VARID) A) B
 WHERE B.RN >= 21
 AND B.RN <= 40;

查询结果:20条记录,执行时间:13.224秒

 

三、分页写法结论及其分析

1、结论:Oracle分页写法必须三层嵌套:写法一的执行效率最高、写法二的执行效率较差(实际测试结果  写法一:写法二=1:426、不同环境测试结果肯定会有偏差)

2、执行效率差异分析

     是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件WHERE ROWNUM <= 40就可以被Oracle推入到内层查询中,这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了。

     而第二个查询语句,由于查询条件BETWEEN 21 AND 40是存在于查询的第三层,而Oracle无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道RN代表什么)。因此,对于第二个查询语句,Oracle最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多。

上面分析的查询不仅仅是针对单表的简单查询,对于最内层查询是复杂的多表联合查询或最内层查询包含排序的情况一样有效。

这里就不对包含排序的查询进行说明了,下一篇文章会通过例子来详细说明。下面简单讨论一下多表联合的情况。对于最常见的等值表连接查询,CBO一般可能会采用两种连接方式NESTED LOOP和HASH JOIN(MERGE JOIN效率比HASH JOIN效率低,一般CBO不会考虑)。在这里,由于使用了分页,因此指定了一个返回的最大记录数,NESTED LOOP在返回记录数超过最大值时可以马上停止并将结果返回给中间层,而HASH JOIN必须处理完所有结果集(MERGE JOIN也是)。那么在大部分的情况下,对于分页查询选择NESTED LOOP作为查询的连接方法具有较高的效率(分页查询的时候绝大部分的情况是查询前几页的数据,越靠后面的页数访问几率越小)。

 

四、ROWNUM的补充说明

对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,而且rownum不能以任何表的名称作为前缀。
举例说明:
例如表:student(学生)表,表结构为:
ID    char(6)      --学号
name    VARCHAR2(10)   --姓名 
create table student (ID char(6), name VARCHAR2(100));
insert into sale values(‘200001‘,‘张一’);
insert into sale values(‘200002‘,‘王二’);
insert into sale values(‘200003‘,‘李三’);
insert into sale values(‘200004‘,‘赵四’);
commit;

(1) rownum 对于等于某值的查询条件
如果希望找到学生表中第一条学生的信息,可以使用rownum=1作为条件。但是想找到学生表中第二条学生的信息,使用rownum=2结果查不到数据。因为rownum都是从1开始,但是1以上的自然数在rownum做等于判断是时认为都是false条件,所以无法查到rownum = n(n>1的自然数)。
SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回记录条数的地方,保证不出错,如:隐式游标)
SQL> select rownum,id,name from student where rownum=1;
 ROWNUM ID NAME
---------- ------ ---------------------------------------------------
  1 200001 张一
SQL> select rownum,id,name from student where rownum =2; 
 ROWNUM ID NAME
---------- ------ ---------------------------------------------------
(2)rownum对于大于某值的查询条件
 如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录
SQL> select rownum,id,name from student where rownum >2;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
那如何才能找到第二行以后的记录呀。可以使用以下的子查询方法来解决。注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
 NO ID NAME
---------- ------ ---------------------------------------------------
  3 200003 李三
  4 200004 赵四
SQL> select * from(select rownum,id,name from student)where rownum>2;
 ROWNUM ID NAME
---------- ------ ---------------------------------------------------
(3)rownum对于小于某值的查询条件
如果想找到第三条记录以前的记录,当使用rownum<3是能得到两条记录的。显然rownum对于rownum<n((n>1的自然数)的条件认为是成立的,所以可以找到记录。
SQL> select rownum,id,name from student where rownum <3;
 ROWNUM ID NAME
---------- ------ ---------------------------------------------------
 1 200001 张一
 2 200002 王二
综上几种情况,可能有时候需要查询rownum在某区间的数据,那怎么办呀从上可以看出rownum对小于某值的查询条件是人为true的,rownum对于大于某值的查询条件直接认为是false的,但是可以间接的让它转为认为是true的。那就必须使用子查询。例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么我们只能写以下语句,先让它返回小于等于三的记录行,然后在主查询中判断新的rownum的别名列大于等于二的记录行。但是这样的操作会在大数据集中影响速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
 NO ID NAME
---------- ------ ---------------------------------------------------
  2 200002 王二
  3 200003 李三
(4)rownum和排序
Oracle中的rownum的是在取数据的时候产生的序号,所以想对指定排序的数据去指定的rowmun行数据就必须注意了。
SQL> select rownum ,id,name from student order by name;
 ROWNUM ID NAME
---------- ------ ---------------------------------------------------
  3 200003 李三
  2 200002 王二
  1 200001 张一
  4 200004 赵四
可以看出,rownum并不是按照name列来生成的序号。系统是按照记录插入时的顺序给记录排的号,rowid也是顺序分配的。为了解决这个问题,必须使用子查询
SQL> select rownum ,id,name from (select * from student order by name);
 ROWNUM ID NAME
---------- ------ ---------------------------------------------------
  1 200003 李三
  2 200002 王二
  3 200001 张一
  4 200004 赵四
这样就成了按name排序,并且用rownum标出正确序号(有小到大)
笔者在工作中有一上百万条记录的表,在jsp页面中需对该表进行分页显示, 便考虑用rownum来作,下面是具体方法(每页
显示20条): 
 “select * from tabname where rownum<20 order by name" 但却发现oracle却不能按自己的意愿来执行,而是先随便
取20条记录,然后再 order by,后经咨询oracle,说rownum确实就这样,想用的话,只能用子查询 来实现先排序,后
rownum,方法如下: 
 "select * from (select * from tabname order by name) where rownum<20",但这样一来,效率会较低很多。 
 后经笔者试验,只需在order by 的字段上加主键或索引即可让oracle先按 该字段排序,然后再rownum;方法不变: 
 “select * from tabname where rownum<20 order by name"
取得某列中第N大的行
select column_name from 
(select table_name.*,dense_rank() over (order by column desc) rank from table_name) 
where rank = &N; 
 假如要返回前5条记录:
  select * from tablename where rownum<6;(或是rownum <= 5 或是rownum != 6) 
假如要返回第5-9条记录:
select * from tablename 
where … 
and rownum<10 
minus 
select * from tablename 
where … 
and rownum<5 
order by name 
选出结果后用name排序显示结果。(先选再排序)
注意:只能用以上符号(<、<=、!=)。
select * from tablename where rownum != 10;返回的是前9条记录。 
不能用:>,>=,=,Between...and。由于rownum是一个总是从1开始的伪列,Oracle 认为这种条件 不成立,查不到记录.
另外,这个方法更快:
select * from ( 
select rownum r,a from yourtable 
where rownum <= 20 
order by name ) 
where r > 10 
这样取出第11-20条记录!(先选再排序再选)
要先排序再选则须用select嵌套:内层排序外层选。 
rownum是随着结果集生成的,一旦生成,就不会变化了;同时,生成的结果是依次递加的,没有1就永远不会有2! 
rownum 是在 查询集合产生的过程中产生的伪列,并且如果where条件中存在 rownum 条件的话,则:
1: 假如 判定条件是常量,则: 
只能 rownum = 1, <= 大于1 的自然数, = 大于1 的数是没有结果的, 大于一个数也是没有结果的 
即 当出现一个 rownum 不满足条件的时候则 查询结束   this is stop key!
2: 当判定值不是常量的时候 
若条件是 = var , 则只有当 var 为1 的时候才满足条件,这个时候不存在 stop key ,必须进行 full scan ,对每个满足其他where条件的数据进行判定 
选出一行后才能去选rownum=2的行……

[Oracle]关于Oracle分页写法的性能分析及ROWNUM说明

标签:his   jsp   游标   而且   集合   oracle   blog   count   判断   

热心网友 时间:2022-04-09 16:58

x.*,rownum no form (...) x where no<?

这里rownum是结果集的序号,也就是no<多少 就取多少数据。永远取不到区间记录集。
(x.*,rownum no from(...)x ) xx where xx.no<? 这里再用xx.no的时候,rownum相当于所有结果集先按行号排序,在根据行号获取大于多少行号和小于多少行号的区间记录集追问x.*,rownum no form (...) x where no<? 这个的no是按结果接标记序号,取小于多少条的数据
(x.*,rownum no from(...)x ) xx where xx.no<? 这个不也是按结果集标记序号,他们标记的序号都应该一样的吧?只不过上面那种只标记到上限就停止了

追答第一句不一样,比如有1000条数据,你要去200到300的记录,第一句是取前200的记录,大于200是取不到的,因为结果集还没生成,rownum没有大于200
第二句,已经生成了结果集,这时候rownum是从1排到1000的,这时候可以取到200到300

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
笔记本电脑的哪些牌子什么牌子的笔记本电脑好 笔记本电脑品牌质量排行榜你知道哪个最耐用全面解析笔记本电脑品牌的质 ... 十大笔记本电脑品牌笔记本电脑推荐品牌 各大汽车电脑品牌厂家官方售后服务电话合辑v3.00 哪种笔记本电脑售后好哪个品牌电脑售后好 各大笔记本电脑品牌售后网点及售后电话汇总解决您笔记本电脑问题的选 ... 如何教育孩子成学霸 学霸的家长是怎样培养孩子的? 聪明的懒孩子怎么变成学霸 学霸孩子怎么培养 异界修真八荒论道在哪 异界修真八荒论道在哪里 宝骏560近光灯不够亮,换什么灯最好 《鬼谷八荒》论道怎么选? 《鬼谷八荒》道种能传几次? 宝骏560的远灯怎么调远?宝骏560近光灯限制怎么调高? 汽车挡风玻璃有10多厘米的裂痕能修补吗? 宝骏560车灯!大灯下面小灯为何总亮着 挡风玻璃裂了能上高速吗? 宝骏560大灯怎么调节才聚光 轿车前挡风玻璃裂了三十厘米还能开车上路吗 宝骏560大灯怎么调节,宝骏560大灯怎么开 修补完挡风玻璃裂痕,多久可以开车? 有什么好看的霸道总裁类型或者黑道的言情小说? 汽车前挡风玻璃裂了,是不是要换新玻璃,会不会开车颠簸全部碎了啊? 推荐几部高冷霸道总裁和呆萌少女的现代言情小说,男主一定要高冷!!! 宝骏560灯光演示视频播放 前挡风玻璃外力影响,裂了,会不会开车炸开啊,需要换新玻璃吗? 前挡风玻璃裂开了 还能跑高速吗 汽车前挡风玻璃左下角出现一道10厘米左右的裂痕,会影响行车安全吗? 鬼谷八荒魔道值是什么? 电脑显示器能连接天猫魔盒当电视用吗 电视盒子可使电脑显示器当电视用? 电脑显示器可以连接机顶盒当电视用吗 具体的操作方法是什么 电脑开机后显示应用程序错误 还连不上网路怎么回事 所有软件都连不上网,但是电脑下方小电脑上显示的连接网络,这是为什 电脑开机界面是这个,然后正常启动进去就连不上网,软件也打不开怎么回事呀? 我家电脑开机后,连不上网,显示应用程序错误是怎么回事,WiFi可以用 电脑开机正常,但开机后总是网络运行很慢,所有的软件都运行不了,只有等网络运行了,才能运行别的,是什么原因 电脑开机显示应用程序错误,而且还连接不上网络。怎么办 台北故宫博物院是哪年建成的? 北京故宫博物院与台北故宫博物院的异同 台北故宫博物院颜色搭配 台北也有一个故宫,两个故宫有何差别? 台湾故宫的博物馆一共有多少件文物? 台北故宫博物院里的文物大多数来源于哪里? 从历史文化角度分析台北故宫博物院属于什么类型的博物馆 台北故宫的文物是不是比北京故宫好 台北故宫博物院藏了多少东陵宝贝 找一篇一千字左右的演讲稿.主题以感恩校园、回馈社会、*梦想等为主题