面试题&实战面试题:数据量大时如何实现深度分页?在面试或准备面试的过程中,你可能会遇到上述问题。答案基本就是分库分表建索引。这是一个标准的正确答案,但现实总是很骨感,所以面试官一般都会问你一个问题。现在工期不足,人员不足,如何实现深度分页?这时候,没有实践经验的同学基本麻木了。所以,请听我说。惨痛的教训首先要明确:深度分页是可以的,但深度随机跳页是绝对禁止的。上图:猜猜,如果我点击第142页360,服务会不会爆炸?像MySQL、MongoDB这样的数据库还可以,而且是专业的数据库。到了ES,性质就不一样了。我们不得不使用SearchAfterApi循环获取数据,这就涉及到内存占用的问题。如果当时代码写得不优雅,可能会直接导致内存溢出。为什么不能允许随机的深度页面跳转?从技术角度来说,为什么不能允许随机深页跳转,或者为什么不推荐深页跳转。MySQL分页的基本原理:SELECT*FROMtestORDERBYidDESCLIMIT10000,20;对于满足条件的10020行,丢掉前面的10000行,返回最后20行。如果是LIMIT1000000,100,则需要扫描1000100行。在高并发应用中,每个查询需要扫描100W以上的行。MongoDB分页的基本原理:db.t_data.find().limit(5).skip(5);同样,随着页码的增加,skip跳过的item也会变大,而这个操作是通过cursor的迭代器实现的,cpu的消耗会非常明显。当页码很大很频繁的时候,难免会爆炸。ElasticSearch从业务的角度来看,ElasticSearch不是一个典型的数据库,它是一个搜索引擎,如果在过滤条件下没有找到想要的数据,继续深入分页也找不到想要的数据。退一步说,如果我们使用ES作为数据库来查询,那么在分页的时候肯定会遇到max_result_window的限制。看,官方告诉你offset上限是10000。查询过程:比如查询501页,每页10条,客户端向节点发送请求,节点将数据广播给各个分片,每个分片返回前5010条数据查询结果给节点,然后对数据进行整合,取出前5010条数据返回给客户端。由此我们可以看出为什么偏移量是有限的。此外,如果使用SearchAfter等滚动API进行深度跳页查询,每次也需要滚动数千条,可能总共需要滚动几百万或者几千万条数据,光是最后20条数据,效率可想而知。带着产品再次上线俗话说,技术解决不了的问题,就交给业务来解决!实习期间深信产品的邪,一定要实现深度分页+跳页。现在要搞定,业务要做如下改动:尽量增加默认的过滤条件,比如:时间段,目的是减少展示的数据量,修改页面跳转的展示方式,改为滚动显示,或者小范围跳转的滚动显示图:通用方案短时间内快速解决方案主要有以下几点:Mandatory:对于排序字段,过滤条件要设置好索引核心:使用页码范围小的已知数据,或者滚动加载的已知数据,额外减少偏移量:如果遇到不好处理的情况,也可以获取冗余数据,进行一定的拦截。性能影响不大。MySQL原始分页SQL:#第一页SELECT*FROM`year_score`where`year`=2017ORDERBYidlimit0,20;#第N页SELECT*FROM`year_score`where`year`=2017ORDERBYidlimit(N-1)*20,20;通过上下文改写为:#XXXX代表已知数据SELECT*FROM`year_score`where`year`=2017andid>XXXXORDERBYidlimit20;没有鬼的话,来点干货吧!SQL优化与诊断一文中提到,LIMIT会在条件满足时停止查询,因此该方案的总扫描量会急剧减少。效率提升最大!ES方案和MySQL一样。这个时候我们可以随意使用FROM-TOApi,不需要考虑最大限制。MongoDB的解决方案基本类似,基本代码如下:相关性能测试:如果非要随机深度跳转页面,产品经理没通过怎么办?没关系,还有一丝机会。SQL优化一文中也提到了MySQL深度分页的处理技巧。代码如下:#反例(耗时129.570s)select*fromtask_resultLIMIT20000000,10;10)bwherea.id=b.id;#Description#task_result表是生产环境的表,总数据量3400万,id为主键,offset为2000万。该方案的核心逻辑是基于聚簇索引。不用回表,快速获取指定偏移量数据的主键ID,然后使用聚簇索引回表查询。此时总数只有10个,效率很高。所以,我们在处理MySQL、ES、MongoDB时,也可以采用同样的方法:限制获取的字段,通过过滤条件和深度分页,只获取主键ID。通过主键ID定向查询所需数据缺陷:偏移量很大时,耗时较长,比如文中的5s本文转载自微信公众号“是Kerwin”,可以关注通过以下二维码。转载本文请联系Kerwin公众号。
