2017-11-28 13:22:27
近段时间关注软件系统架构,听到身边同事经常念叨着“分页”,觉得有必要复习一下这一块知识。温故而知新。
分页,是一种将所有数据分段展示给用户的技术。用户每次看到的不是全部的数据,而是其中的一部分,用户可以通过制定页码或是翻页的方式转换可见内容。类似于翻看书页。
以典型的三层架构中,从请求发起到返回数据的整个过程
在 SQL 语句处理完毕后,在三个地方均可以进行分页:
1. 数据库
2. Web Applicaiton
3. Browser 客户端
判断的标准是 速度 时间。
DB, Applicaiton Server, Browser 通过网络连接。
如果网络传输的数据量越少,则客户端获得响应的速度越快。
1. DB Server 和 Web Server 的处理能力一般比客户端强很多,因此不选择在客户端分页。
2. 如果在 Web Server 端分页的话,大部分被过滤掉的数据还是被传输到了 Web 应用服务器端。不如在 DB Server 端分页。
因此比较好的分页做法应该是:
每次翻页的时候只从数据库里检索页面大小的块区的数据。
这样虽然每次翻页都需要查询数据库,但查询出来的记录数很少,网络传输数据量不大,
如果使用连接池更可以略过最耗时的建立数据库连接过程。
在数据库端有各种成熟的优化技术用于提高查询速度,比在 Application Server 做缓存有效的多。
MySql 使用 limit 语句进行分页。
Oracle 使用 ROWNUMBER 伪列,和 OLAP 函数 ROW_NUMBER 以处理内部的页码计算,并控制分页数据
显示的嵌套子查询。
《Oracle SQL 疑难解析》 P96
在网页上显示查询结果,在每页上显示一部分结果。通过结果集上的页码信息,用户可以前后翻页查看数据。
其本质是定义数据集的子集,无论是放在网页上,还是放在报表中,支持后面的输出。
不需要修改基础数据,以显式增加页码或者分区信息。
而是使用 ROWNUMBER 为例 或 OLAP 函数 ROW_NUMBER 以处理内部的页码计算,并控制分页数据显示的嵌套
子查询。
以 Oracle orcl 实例 中 OE schema 的 Production_Information
两种方式:
1. ROWNUM 采用 Oracle 原有的技术支持和内置的优化器, 隐含的的排序速度比常规的排序更快。
2. ROW_NUM 方式则更通用,能让我们以不同于标准的 Order By 子句的方式来给行进行编号.
还可以用其他的 OLAP 函数 如 RANK 和 DENSE_RANK 来改写之前的处理方式,以应对不同的分页需求,例如将某些行在“固定”的位置
第一种实现方式 ROWNUM
两个疑问:
1. 子查询中用 ROWNUM 的列别名 ” r " ,而不是在外层 Select 语句中直接使用 ROWNUM ?
2. 不用 Between And 语句来简化整个语句设计。
以上的结果是没有返回任何行。
原因在于 ROWNUM 的机制使然, ROWNUM 仅仅在基本查询条件满足 (尚未排序和聚集)时指定值,ROWNUM 也总是从1开始。指定1之后,再增加到2,一次类推。
通过移除别名,新的 ROWNUM 值就不会在外层查询中生成,这是在问第一个候选值是否大于或等于41.结果为否,所以那一行就丢弃了,而 ROWNUM 值就不会再增加,一直是1,后续的行也不会满足条件, 最后的结果也就是没有返回任何行。
使用 BETWEEN 的变体,也有同样的问题。
在外层的 SQL 中, 则用别名作范围限定结果集的返回。
第二种实现方式 OLAP ROW_NUM() 函数实现