mysql百万级数据分页查询缓慢优化-实战
- 作为后端攻城狮,在接到分页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多字段
- 重点是在传统分页方案上遇到的两个问题
是谁来自江河湖海,却囿于昼夜厨房与爱