MySQL分页查询及优化
一、分页
什么是分页
一般在客户端实现分页功能的时候,要显示当前页的数据、当前所在页数、临近页面的按钮以及总页数等等。这些数据随着翻页的进行能够动态的变化,为了实现这样的效果,一般会采取两种办法:真分页和假分页。这样的划分方式是从与数据库的交互方式出发的,是每次翻页时都进行查询还是一次性查出所有的数据。
真分页
真分页指的是每次在进行翻页时都只查询出当前页面的数据,特点就是与数据库的交互次数较多,但是每次查询的数据量较少,数据也不需要一直保存在内存中。适用于数据量比较大的场景,数据不适合全量查出的情况。
- 假分页假分页指的是对于要显示的数据一次性全部查出,一直存在在服务端或客户端,在前端进行分页或由服务端控制分页。将根据当前所在页来计算应该显示的数据所在下标,用循环取出目标数据。只有当会话断开或页面关闭,相应的资源才会被释放。
- 缓存层真分页和假分页都要和数据库进行交互,对于真分页来说不需要担心数据同步的问题,因为每次都是查询出最新的,但是数据库的负担会很重,尤其是用户量大的情况下。假分页可以在一定程度上减轻数据库的压力,但是数据不能及时得到同步,除非重新请求或页面刷新。一般在企业中会有缓存层的存在,既能有效降低数据库的压力,又能及时的进行数据同步。在对数据库中的数据进行修改后,要将变更后的数据及时同步到缓存层,在进行数据查询时从缓存层获取。
二、MySQL实现分页
LIMIT用法
LIMIT出现在查询语句的最后,可以使用一个参数或两个参数来限制取出的数据。其中第一个参数代表偏移量:offset(可选参数),第二个参数代表取出的数据条数:rows。
单参数用法
当指定一个参数时,默认省略了偏移量,即偏移量为0,从第一行数据开始取,一共取rows条。
1 | /* 查询前5条数据 */ |
双参数用法
当指定两个参数时,需要注意偏移量的取值是从0开始的,此时可以有两种写法:
1 | /* 查询第1-10条数据 */ |
- 分页公式
总页数计算
在进行分页之前,我们需要先根据数据总量来得出总页数,这需要用到COUNT函数和向上取整函数CEIL,SQL如下:
1 | /* 获得数据总条数 */ |
核心信息
当前页:pageNumber
每页数据量:pageSize
据此我们可以总结出,LIMIT所需要的两个参数计算公式如下:
1 | offset:(pageNumber - 1) * pageSize |
三、查询优化
但是上述查询在偏移量特别大的情况下,可能会出现效率问题
下面是一个实例:
1 | select * from orders_history where type=8 limit 1000,10; |
该条语句将会从表 orders_history 中查询第1000条数据之后的10条数据,也就是第1001条到第1010条数据。
数据表中的记录默认使用主键(一般为id)排序,上面的结果相当于:
1 | select * from orders_history where type=8 order by id limit 10000,10; |
此处缺少实验数据,以后补充
这种分页查询方式会从数据库第一条记录开始扫描,所以越往后,查询速度越慢,而且查询的数据越多,也会拖慢总查询速度。
1.使用子查询优化
这种方式先定位偏移位置的 id,然后往后查询,这种方式适用于 id 递增的情况。
1 | select * from orders_history where type=8 limit 100000,1; |
2.使用 id 限定优化
这种方式假设数据表的id是连续递增的,则我们根据查询的页数和查询的记录数可以算出查询的id的范围,可以使用 id between and 来查询:
1 | select * from orders_history where type=2 |
这种查询方式能够极大地优化查询速度,基本能够在几十毫秒之内完成。限制是只能使用于明确知道id的情况,如果表用的是分布式 id (如:UUID、雪花算法),则不适用。


