一、与产品商讨 修改需求
- 后端工程师,在接到分页list需求的时候,内心是这样的
- 画面是这样的
- 代码大概是这样的
- select count(id) from … 查出总数
- select * from …. limit m,n 查出分页数据
- 和前端的交互是这样的
- 你传给我查询条件和pageNum、pageSize
- 我给你返回total、resultList
- 恩,可以开始预估开发时间了
- 结果出来的时候是这样的
- 在点击后面几页的时候发现数据加载很慢。不好,一开始没想到数据量是这个级别的,慢SQL监控已经开始预警
- 定位到原因有两个
- select count(*) 总量会扫全表
- limit m,n 当偏移量m很大的时候,查询每次都要先扫到m条满足条件的记录
- 其他人一定也遇到过这个问题,打开百度还没开始搜索就找到了一个解决方案,百度是这样做的
- (正解)我去,这不是耍流氓吗
- 没有总数,就不需要count,第一个问题解决
- limit m,n 百度出来的解决方案都是加一个唯一标识去记录上一次查询的记录在哪里
- 百度这种做法是搜索引擎自带的分页,不过mysql分页同样可以借鉴,找来产品大大沟通一发
- “面对这么多的数据,只要把新的数据放到前面,用户不会care后面的数据,是不是可以把页码干掉”
- “ 用户也不会管我们到底有多少条记录,来这里也只是做检索而已,总数也可以去掉的,如果要统计数据量我们再单独统计”
- 。。。理由还可以有很多,产品大大还是很好说话的
- 最后设计出来是这样的
- 代码实现是这样的
- id是自增主键
- select * from … where id > y order by id limit n (向下翻页)
- select * from … where id < y order by id desc limit n (向上翻页)
- 和前端的交互是这样的
- 你告诉我是向上翻页还是向下翻页,给我当前页第一条(上一页)或者最后一条(下一页)记录的id
- 我给你数据数据
- 总结
- 重点是在传统分页方案上遇到的两个问题
- select count(*) 总量会扫全表
- limit m,n 当偏移量m很大的时候,查询每次都要先扫到m条满足条件的记录
- 解决方案是产品和技术共同确认的结果,如果产品不接受,此方案不可行
- 实际开发中还会碰到的问题
- 上一页/下一页、没有数据的处理方式
- 查询自身带有排序条件,需要order by多字段
二、优化sql查询语句
1.子查询优化法
先找出第一条数据,然后大于等于这条数据的id就是要获取的数据
缺点:数据必须是连续的,可以说不能有where条件,where条件会筛选数据,导致数据失去连续性
实验下
mysql> set profi=1;
Query OK, 0 rows affected (0.00 sec)
mysql> select count(*) from Member;
+———-+
| count(*) |
+———-+
| 169566 |
+———-+
1 row in set (0.00 sec)
mysql> pager grep !~-
PAGER set to ‘grep !~-‘
mysql> select * from Member limit 10, 100;
100 rows in set (0.00 sec)
mysql> select * from Member where MemberID >= (select MemberID from Member limit 10,1) limit 100;
100 rows in set (0.00 sec)
mysql> select * from Member limit 1000, 100;
100 rows in set (0.01 sec)
mysql> select * from Member where MemberID >= (select MemberID from Member limit 1000,1) limit 100;
100 rows in set (0.00 sec)
mysql> select * from Member limit 100000, 100;
100 rows in set (0.10 sec)
mysql> select * from Member where MemberID >= (select MemberID from Member limit 100000,1) limit 100;
2.倒排表优化法
倒排表法类似建立索引,用一张表来维护页数,然后通过高效的连接得到数据
缺点:只适合数据数固定的情况,数据不能删除,维护页表困难
3.反向查找优化法
当偏移超过一半记录数的时候,先用排序,这样偏移就反转了
缺点:order by优化比较麻烦,要增加索引,索引影响数据的修改效率,并且要知道总记录数
,偏移大于数据的一半
引用
limit偏移算法:
正向查找: (当前页 – 1) * 页长度
反向查找: 总记录 – 当前页 * 页长度