文章目录
- 前言
- 数据表的准备
- 分页sql
- 1、简单分页实现
- 2、排序分页
- 3、排序优化
前言
在平时的开发中,Oracle
的分页查询用的特别多,接下来不止是说使用,更讲分页sql写法的原理。
数据表的准备
创建一张数据表,并填充大量的数据。
create table XJ_TEST_LTOH
(
stuid VARCHAR2(20),
stuname VARCHAR2(40),
coursename VARCHAR2(40),
score INTEGER
)
并增加数据信息。
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201001', '张三', '数学', 40);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201001', '张三', '语文', 50);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201001', '张三', '理综', 120);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201011', '李四', '数学', 32);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201011', '李四', '语文', 45);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201011', '李四', '理综', 123);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201031', '王五', '数学', 54);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201031', '王五', '语文', 56);
insert into xj_test_ltoh (STUID, STUNAME, COURSENAME, SCORE)
values ('sc202201031', '王五', '理综', 100);
执行后,数据表信息如下所示:
分页sql
1、简单分页实现
在Oracle
中,分页通常会采用一个叫ROWNUM
的伪列
进行实现。
扩展知识:伪列有 rowid (每条数据的物理地址) 和 rownum (数据的序号) 两种。
正常来说,根据数据表与rownum相结合,就能实现表的分页操作。
select rownum,t.* from xj_test_ltoh t
比如,只显示第一页的数据,每页显示5条记录数。
select rownum,t.* from xj_test_ltoh t where rownum <= 5
但是,如果查询第二页呢?
select rownum,t.* from xj_test_ltoh t where rownum <= 10 and rownum >5
执行后,并不会有任何结果。
【原因】:
rownum 只允许使用
<
或者<=
。
【注意:】小细节
rownum是在数据逐条扫描的时候,才会生成,如果一开始就指明条件 rownum>10 ,则将导致查询sql语句无效,也就是无数据集。
如何解决上述的问题呢?
可以考虑
子查询
来进行实现。
既然 rownum 只允许使用
<
或者<=
,那么先查询数据,在做一个from
子查询,得到的结果附带 rownum 属性值,将rownum值作为一个数据集的列属性(当作一个表的列字段),就能使用>
进行截取了!
select * from
(select rownum r,t.* from xj_test_ltoh t where rownum <= 10)
where r > 5
或者
select * from
(select rownum r,t.* from xj_test_ltoh t )
where r > 5 and r <= 10
但是这么写会存在一个bug,先不说bug是什么样的,接下来进行排序后再分页,这个bug就会出现。
2、排序分页
还是上面的表,先根据 score 成绩
字段进行降序排序
,再进行数据的分页操作。
select rownum r,t.* from xj_test_ltoh t order by t.score desc
但是,发现问题了没有,上面的 rownum 是一个乱序的,并不能满足分页操作。
如何解决上面的问题呢?
依然是先查询,再根据查询到的结果集,通过from子查询绑定rownum,再分页操作。
select rownum r,t2.* from (select * from xj_test_ltoh t order by t.score desc) t2
然后,再进行分页操作
select * from (
select rownum r,t2.* from (select * from xj_test_ltoh t order by t.score desc) t2
)
where r > 5 and r <= 10
3、排序优化
进行sql的编写,还需要考虑到数据特别多的情况下,如何保证高效的查询分页操作。
在上面的sql中,子查询 select rownum r,t2.* from (select * from xj_test_ltoh t order by t.score desc) t2
此处是查询了全表
。如果数据量特别大,将导致全表检索,耗时问题。
解决方式也很简单
将全表查询的数据量缩小。
先进行排序但限定查询后的数据范围,再将已经初步缩小范围的查询结果作为集合,再次查询集合继续截取掉无用数据,如下所示sql:
select * from (
-- 初步缩小范围
select A.*,rownum rn from(
select * from xj_test_ltoh order by score desc
) A where rownum <= 10
) where rn > 5 -- 再次截取掉无用数据