面试题:在数据量很大的状况下,怎么实现深度分页?mysql
你们在面试时,或者准备面试中可能会遇到上述的问题,大多的回答基本上是分库分表建索引
,这是一种很标准的正确回答
,但现实老是很骨感,因此面试官通常会追问你一句,如今工期不足,人员不足,该怎么实现深度分页?面试
这个时候没有实际经验的同窗基本麻爪,So,请听我娓娓道来。sql
首先必须明确一点:深度分页能够作,可是深度随机跳页绝对须要禁止。mongodb
上一张图:数据库
大家猜,我点一下第142360
页,服务会不会爆炸?并发
像MySQL
,MongoDB
数据库还好,自己就是专业的数据库,处理的很差,最多就是慢,但若是涉及到ES
,性质就不同了,咱们不得不利用 SearchAfter
Api,去循环获取数据,这就牵扯到内存占用的问题,若是当时代码写的不优雅,直接就可能致使内存溢出。elasticsearch
从技术的角度浅显的聊一聊为何不能容许随机深度跳页,或者说为何不建议深度分页高并发
分页的基本原理:post
SELECT * FROM test ORDER BY id DESC LIMIT 10000, 20;
LIMIT 10000 , 20的意思扫描知足条件的10020行,扔掉前面的10000行,返回最后的20行。若是是LIMIT 1000000 , 100,须要扫描1000100 行,在一个高并发的应用里,每次查询须要扫描超过100W行,不炸才怪。性能
分页的基本原理:
db.t_data.find().limit(5).skip(5);
一样的,随着页码的增大,skip 跳过的条目也会随之变大,而这个操做是经过 cursor 的迭代器来实现的,对于cpu的消耗会很是明显,当页码很是大时且频繁时,必然爆炸。
从业务的角度来讲,ElasticSearch
不是典型的数据库,它是一个搜索引擎,若是在筛选条件下没有搜索出想要的数据,继续深度分页也不会找到想要的数据,退一步讲,假如咱们把ES
做为数据库来使用进行查询,在进行分页的时候必定会遇到max_result_window
的限制,看到没,官方都告诉你最大偏移量限制是一万。
查询流程:
由此能够看出为何要限制偏移量,另外,若是使用 Search After
这种滚动式API进行深度跳页查询,也是同样须要每次滚动几千条,可能一共须要滚动上百万,千万条数据,就为了最后的20条数据,效率可想而知。
俗话说的好,技术解决不了的问题,就由业务来解决!
在实习的时候信了产品的邪,必须实现深度分页 + 跳页,现在必须拨乱反正
,业务上必须有以下更改:
滚动显示参考图:
小规模跳页参考图:
短期内快速解决的方案主要是如下几点:
原分页SQL:
# 第一页 SELECT * FROM `year_score` where `year` = 2017 ORDER BY id limit 0, 20; # 第N页 SELECT * FROM `year_score` where `year` = 2017 ORDER BY id limit (N - 1) * 20, 20;
经过上下文关系,改写为:
# XXXX 表明已知的数据 SELECT * FROM `year_score` where `year` = 2017 and id > XXXX ORDER BY id limit 20;
在 没内鬼,来点干货!SQL优化和诊断 一文中提到过,LIMIT会在知足条件下中止查询,所以该方案的扫描总量会急剧减小,效率提高Max!
方案和MySQL
相同,此时咱们就能够随用所欲的使用 FROM-TO
Api,并且不用考虑最大限制的问题。
方案基本相似,基本代码以下:
相关性能测试:
若是你没有杠过产品经理,又该怎么办呢,不要紧,还有一丝丝的机会。
在 SQL优化 一文中还提到过MySQL
深度分页的处理技巧,代码以下:
# 反例(耗时129.570s) select * from task_result LIMIT 20000000, 10; # 正例(耗时5.114s) SELECT a.* FROM task_result a, (select id from task_result LIMIT 20000000, 10) b where a.id = b.id; # 说明 # task_result表为生产环境的一个表,总数据量为3400万,id为主键,偏移量达到2000万
该方案的核心逻辑即基于聚簇索引
,在不经过回表
的状况下,快速拿到指定偏移量数据的主键ID,而后利用聚簇索引
进行回表查询,此时总量仅为10条,效率很高。
所以咱们在处理MySQL
,ES
,MongoDB
时,也能够采用同样的办法:
瑕疵:当偏移量很是大时,耗时较长,如文中的 5s
参考文章:MongoDB中文社区
感谢 @程大设计师 为我倾情设计的二维码😜
若是以为对你有用的话,不要忘记点个赞啊~