分页查询

来源:互联网 发布:社会主义中级阶段知乎 编辑:程序博客网 时间:2024/06/05 20:32

这是一个特别基础而且又很重要的话题,很多人知道该怎么做,但是并不知道什么时候做,有个朋友前阵子突然来问我,如果想要实现一个可翻页列表该如何做的时候,我告诉他,做分页查询,然后他找了些资料,最后告诉我,依然不会。
那今天简单的说一下分页查询如何实现。老套路,介绍之前要先把理论基础铺垫好。
分页查询大致有两个模式,我们一般称为:假分页和真分页。
假分页是指一次性查询出所有结果,将数据保存在内存中,然后后续的查询在内存中读取数据,实现分页的目的。这种方式可以预见的是,第一次数据量加载会特别大,所以速度很慢,但是后续的查询因为是在内存中实现的,所以效率很高。但是这里同样存在一个问题,视内存大小而定,这种查询有溢出风险,所以仅仅在数据量较小的时候建议使用。
真分页是指每次从数据库中查询出N条数据,而非一次性的读取所有数据。这样做每次的查询都需要SQL来实现,但是读取是稳定的,效率一样,尤其在数据量很大的时候,这种查询实现是很有价值的,对内存的占用也很友好。
接下来说说实现方式,因不同的数据库对分页的支持也不大一样,这里就拿Oracle和MySql来介绍。
MySql对分页的支持相对简单,举个例子吧:

select * from student order by id limit 10,11;

limit后的第一个参数是查询起点,第二个参数是需要查询的行数。简简单单不罗嗦,但是这种形式有缺陷,越往后效率越低,当然有很多优化查询的方法,这里不做介绍,有兴趣的朋友请自行查阅limit优化查询。
Oracle的分页查询就不那么友好了,非常的麻烦,至少我这么觉得,不过形式也是固定的,只要理解了,也不难。格式如下:

    select * from (            select e.*,rownum r from (                   select * from emps order by empno            ) e      ) where r between 11 and 20

上面代码中between后是查询的起止位置,后面会做详细的说明。而rownum关键字是需要特殊说明的。
Rownum被称作伪列,有一些有趣的特性,它是oracle系统顺序分配的查询返回的行的编号,第一行是1,依次递增1,但是这个字段不能以任何表的名称作为前缀。
举个例子,比如说我在查询学生记录的时候,我希望得到rownum>2的数据行(如果查询出大于两行的数据,那么第二行的rownum为2),所以我的子查询写成如下形式:

Where rownum >2;

这时候我们不会得到任何结果,原因在于oracle认为rownum都是从1开始的,那么我判断rownum>2是永远不会成立的,哪怕=2也不行。由此我们还可以得出这样一个结论,判断小于是可行的,如果判断<2的话,至少会得到一条满足条件的记录。
那么如何判断大于某rownum值的记录呢?这里有个小技巧,我们可以将其作为子查询的结果集,对结果集再次查询,此时rownum就会被当初普通字段对待,再次进行数值限定的时候就可以了,但是需要注意的是,我们在初代查询的时候需要把rownum进行别名设置,不然无法区分rownum究竟是子查询列还是主查询列。举个例子吧:

select * from(select rownum no, name from student) where no >2; 

到此为止,我们回过头再去看上面Oracle的分页查询模式,是不是不再难懂了呢?
接下来,要介绍一个计算方法,如何计算分页的起止记录数呢?其实是有个推导过程的,不过这里不好说明,有兴趣的朋友自行推导,我只给出结果:
起点值:((n - 1) * pageSize + 1)和终点值:(n * pageSize)
将起止值替换到between-and中,就可以了。不过,这个模式依然是有优化空间的,比如说我们在子查询中限制查询记录的最大值,将其后的记录忽略,并且在主查询中限制最小值,这样一来从数据库中获得的记录数量就得到了减少,增加了查询效率,减轻了内存负担。

0 0