枫叶居

桃李春风一杯酒,江湖夜雨十年灯

0%

MySQL分页

转载说明:本文章为作者原创,转载请标注原文地址

公司最近上线了“订单管理系统”,系统内有比较多的分页展示逻辑,所以我单独拿出了点时间,对MySQL的分页做了总结。

提到MySQL分页,我们通常会首先考虑,使用偏移量offset+limit的办法实现。下面以实现目标:
查询订单表order,并按订单创建时间create_time,降序排序,每页50条记录
,为例进行说明。首先我们想到的sql语句如下:

1
select *from `order` order by `create_time` desc limit 0, 50;

多次执行该操作,随着页数增加(即:偏移量增大),该查询语句的性能随之下降,耗时比较明显。当并发量上来时,这对MySQL数据库的压力是致命的。以翻页至200页为例,MySQL会查询200 * 50条记录,最后只返回50条记录,前面的200 * (50 - 1)条记录,将会被丢弃。

因为订单的属性很多,所以并无法为每一列建立索引(当然为每一列都建立索引,是简单粗暴的)。优化此类分页查询的一个最简单的办法,尽可能使用索引覆盖扫描,而不是查询所有列,然后在关联返回所需要的列。优化后的SQL语句如下所示:

1
select *from `order` inner join (select id from `order` order by `create_time` limit desc 10000, 50) as `tmp` using(`id);

这里MySQL扫描了尽可能少的页面,获取需要访问的记录后,然后再去关联查询,获取了所需的列,该种用法还存在若干类似的变种。

最后,也是我们确定的技术选型。推荐的用法,前端每次查询都传入上次查询记录的max_id,或者min_id传递给我们,然后根据id的索引去优化该操作。(注:只有id列的单调性与目标列的单调性一致时可采用该方案)产品设计上,我们不返回具体的页数,只提供了当前页,前后10页跳页的功能,解决了该问题。

向后翻页

1
select *from `order` order by `create_time` desc where `id` < min_id limit 50;

向前跳页

1
2
select *from `order` order by `create_time` desc where
`id` < min_id limit 450, 50;

向前翻页

1
select *from `order` order by `create_time` desc where `id` > max_id limit 50;

向后跳页

1
select *from `order` order by `create_time` desc where `id` > max_id limit 450, 50;

当数据库,采用分库分表,或者中间件时的分页操作,较为复杂,需要根据具体情况确定,本次不做陈述。

坚持原创技术分享,您的支持将鼓励我继续创作!