在分析如何解决大分页问题之前,首先要明确什么是大分页?
大分页也就是分页查询场景中,分页page比较靠后的查询,这往往会带来性能问题,也就是常说的大分页问题,比如常见的SQL
SELECT * FROM tablewhere kid=1342 and type=1 order id asc limit 149420 , 20
。
产生大分页问题原因是什么呢?
这个是数据存储介质本身的查询实现原理决定的,分页查询场景,是按照某个顺序进行查询,分页靠后的查询请求,需要将按照该顺序排序的之前所有页的数据给排除掉,然后取对应页数据返回。该问题瓶颈主要就是排除掉之前页数据这里,比如DB(MySQL)和ES(elasticsearch)都存在该问题。
分页查询,一般使用场景包括 业务查询展示 和 全量数据查询 这两种,实际数据分页查询中,都是首先经过业务服务然后到存储层读取数据,那么优化的话可以在业务服务层做,也可以在存储层来做。下面就按照业务服务层优化和存储层优化两个方面分别讨论。
首先来看业务服务层优化这个场景,该场景下我们可以增加id(数据主键ID,比如MySQL的主键id或者ES中的document id)作为查询条件方式来优化,增加的id一般和数据顺序相对应,比如asc顺序的话一般是取当前页最大id作为下一页的id条件,desc顺序的话是取当前页最小id作为下一页的id条件,使用这种方式的话,缺点是对数据变动感知不友好,如果排序列不是id并且不唯一,可能导致数据串页或者缺失问题。
从业务实际使用场景的角度来看,有多少业务查询是需要真正到大分页查询呢?其实绝大部分的数据查看都只会看前面的一些数据,如果真的需要看后面的数据该怎么办呢?这个时候可以从业务规则层面上来『规避』它,比如建议用户通过限定一些查询条件来查看等,该场景下最好是给予一些友好提示来说明下。
除了增加id作为查询条件方式来优化之外,还可以使用游标或者视图的方式来优化,这种一般就是基于存储层优化来实现的了。比如ES中的scroll查询,它的实现就是在query阶段将document id结果集保留下来,后续批量查询时指定游标后即可获取对应size大小的数据了。ES的scroll一般适用于全量数据查询中,不太适合于前端交互的业务查询展示场景。注意基于游标或者视图查询方式,缺点也是对数据变动感知不太友好。
对于ES的scroll更详细的流程来说是,它先做一次初始化搜索把所有符合搜索条件的结果缓存起来生成一个快照,然后持续地、批量地从快照里拉取数据直到没有数据剩下。而这时对索引数据的插入、删除、更新都不会影响遍历结果,因此scroll 并不适合用来做实时搜索。Scan是搜索类型,告诉Elasticsearch不用对结果集进行排序,只要分片里还有结果可以返回,就返回一批结果。scroll- scan使用中不能跳页获取结果,必须一页接着一页获取。