上亿数据怎么玩深度分页?兼容MySQL + ES + MongoDB
itomcoil 2025-07-27 21:15 2 浏览
推荐学习
面试题 & 真实经历
面试题:在数据量很大的情况下,怎么实现深度分页?
大家在面试时,或者准备面试中可能会遇到上述的问题,大多的回答基本上是分库分表建索引,这是一种很标准的正确回答,但现实总是很骨感,所以面试官一般会追问你一句,现在工期不足,人员不足,该怎么实现深度分页?
这个时候没有实际经验的同学基本麻爪,So,请听我娓娓道来。
惨痛的教训
首先必须明确一点:深度分页可以做,但是深度随机跳页绝对需要禁止。
上一张图:
你们猜,我点一下第142360页,服务会不会爆炸?
像MySQL,MongoDB数据库还好,本身就是专业的数据库,处理的不好,最多就是慢,但如果涉及到ES,性质就不一样了,我们不得不利用 SearchAfter Api,去循环获取数据,这就牵扯到内存占用的问题,如果当时代码写的不优雅,直接就可能导致内存溢出。
为什么不能允许随机深度跳页
从技术的角度浅显的聊一聊为什么不能允许随机深度跳页,或者说为什么不建议深度分页
MySQL
分页的基本原理:
SELECT * FROM test ORDER BY id DESC LIMIT 10000, 20;
LIMIT 10000 , 20的意思扫描满足条件的10020行,扔掉前面的10000行,返回最后的20行。如果是LIMIT 1000000 , 100,需要扫描1000100 行,在一个高并发的应用里,每次查询需要扫描超过100W行,不炸才怪。
MongoDB
分页的基本原理:
db.t_data.find().limit(5).skip(5);
同样的,随着页码的增大,skip 跳过的条目也会随之变大,而这个操作是通过 cursor 的迭代器来实现的,对于cpu的消耗会非常明显,当页码非常大时且频繁时,必然爆炸。
ElasticSearch
从业务的角度来说,ElasticSearch不是典型的数据库,它是一个搜索引擎,如果在筛选条件下没有搜索出想要的数据,继续深度分页也不会找到想要的数据,退一步讲,假如我们把ES作为数据库来使用进行查询,在进行分页的时候一定会遇到max_result_window的限制,看到没,官方都告诉你最大偏移量限制是一万。
查询流程:
- 如查询第501页,每页10条,客户端发送请求到某节点
- 此节点将数据广播到各个分片,各分片各自查询前 5010 条数据
- 查询结果返回至该节点,然后对数据进行整合,取出前 5010 条数据
- 返回给客户端
由此可以看出为什么要限制偏移量,另外,如果使用 Search After 这种滚动式API进行深度跳页查询,也是一样需要每次滚动几千条,可能一共需要滚动上百万,千万条数据,就为了最后的20条数据,效率可想而知。
再次和产品对线
俗话说的好,技术解决不了的问题,就由业务来解决!
在实习的时候信了产品的邪,必须实现深度分页 + 跳页,如今必须拨乱反正,业务上必须有如下更改:
- 尽可能的增加默认的筛选条件,如:时间周期,目的是为了减少数据量的展示
- 修改跳页的展现方式,改为滚动显示,或小范围跳页
滚动显示参考图:
小规模跳页参考图:
通用解决方案
短时间内快速解决的方案主要是以下几点:
- 必备:对排序字段,筛选条件务必设置好索引
- 核心:利用小范围页码的已知数据,或者滚动加载的已知数据,减少偏移量
- 额外:如果遇到不好处理的情况,也可以获取多余的数据,进行一定的截取,性能影响并不大
MySQL
原分页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!
ES
方案和MySQL相同,此时我们就可以随心所欲的使用 FROM-TO Api,而且不用考虑最大限制的问题。
MongoDB
方案基本类似,基本代码如下:
相关性能测试:
如果非要深度随机跳页
如果你没有杠过产品经理,又该怎么办呢,没关系,还有一丝丝的机会。
在 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时,也可以采用一样的办法:
- 限制获取的字段,只通过筛选条件,深度分页获取主键ID
- 通过主键ID定向查询需要的数据
瑕疵:当偏移量非常大时,耗时较长,如文中的 5s
作者:Kerwin_
原文链接:
https://juejin.im/post/5f0de4d06fb9a07e8a19a641
相关推荐
- 字符串可以这样加索引,你知吗?(字符串怎么加)
-
相信大多数小伙伴跟咔咔一样,给字符串添加索引从未设置过长度,今天就来聊聊如何正确的给字符串加索引。一、如何建立索引大多数系统都会存在用户表,并且系统初始设计使用了手机号码登录的。这是产品提出了一个需求...
- MySQL高频函数Top10!数据分析效率翻倍,拒绝无效加班!
-
引言:为什么你的SQL代码又臭又长?“同事3行代码搞定的事,你写了30行?”“每次处理日期、字符串都抓狂,疯狂百度?”——不是你不努力,而是没掌握这些高频函数!本文精炼8年数据库开发经验,总结出10个...
- 上亿数据怎么玩深度分页?兼容MySQL + ES + MongoDB
-
推荐学习阿里P8MySQL,基础/索引/锁/日志/调优都不误,一锅深扒端给你“吃”完这本Java性能调优实战,MySQL+JVM+Tomcat等问题一键全消面试题&真实经历面试题:在数据量很大的情...
- Hive如何比较两张表所有字段的一致性
-
前言随着MySQL技术发展,通过垂直或水平拆分能够支持相当大的数据量,目前很多公司把SQLServer、Oracledb或其他数据库迁移到MySQL上,迁移数据量很大(数据库已经水平拆分成很多Sha...
- MySql:函数盘点(mysql函数用法)
-
一、MySQL函数1、数学函数常用的有:(1)ABS()绝对值(2)CEILING()大于等于我的最小整数(天花板)(3)FLOOR()小于等于我的最大整数(地板)(4)RAND()返回0~1...
- mysql的截取函数用法详解(mysql截取字符串函数的sql语句)
-
substring()函数测试数据准备:用法:以下语法是mysql自动提示的1:substirng(str,pos):从指定位置开始截取一直到数据完成str:需要截取的字段的pos:开始截取的位置。从...
- mysql拼接函数讲解及配合截取函数使用
-
在上一篇我们讲解了mysql的截取函数用法。本篇我们将讲解mysql的拼接函数以及配合截取函数实现当留言数字过多省略显示的场景。concat函数:把参数连成一个长字符串并返回(任何参数是NULL时返回...
- MySQL实现字段分割(一行转多行)(mysql 分割)
-
先看一下数据结构,我这里字段比较少,只弄了最重要的部分根据我们上次学到的LEFT()函数进行分组SELECTLEFT(provinces,6),COUNT(1)FROM`region_map_c...
- MySQL(143)如何优化分页查询?(mysql高效分页查询)
-
优化分页查询是提升数据库性能和用户体验的重要手段。特别是在处理大数据集时,分页查询的效率对系统性能有显著影响。以下是优化分页查询的详细步骤和代码示例。一、传统分页查询传统的分页查询使用OFFSET...
- Go语言实现连接MySql基础操作(golang mysql orm)
-
在Go中,可以使用database/sql包来连接和操作MySQL数据库。以下是一个简单的示例程序,它演示了如何连接MySQL数据库并执行查询操作:packagemainimpo...
- MySQL 如何巧妙解决 Too many connections 报错?
-
1.背景在日常的MySQL运维中,难免会出现参数设置不合理,导致MySQL在使用过程中出现各种各样的问题。今天,我们就来讲解一下MySQL运维中一种常见的问题:最大连接数设置不合理,一旦...
- MYSQL数据同步(mysql数据同步机制)
-
java开发工程师在实际的开发经常会需要实现两台不同机器上的MySQL数据库的数据同步,要解决这个问题不难,无非就是mysql数据库的数据同步问题。但要看你是一次性的数据同步需求,还是定时数据同步,亦...
- Go语言MySQL的简单应用(go mysql prepare)
-
要在Go中处理MySQL数据库,可以使用第三方包,例如go-sql-driver/mysql。以下是一个简单的示例代码:packagemainimport("dat...
- 最简洁详细的SSM框架整合(ssm框架完整的功能流程)
-
创建项目和SSM框架整合思路一、创建项目因为后面会配置springMVC,所以用IDEA的web骨架创建一个maven项目。创建项目目录如下,同时,项目需要的包和文件已手动创建好了:项目目录上图中,a...
- 部署canal server 1.1.5,消费mysql信息,订阅测试
-
一、CanalServer的核心架构CanalServer是阿里巴巴开源的MySQLbinlog增量订阅与消费组件,其架构设计围绕高可用、高性能、低延迟三大目标构建,主要包含以下核心...
- 一周热门
- 最近发表
- 标签列表
-
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)
- shutil.copy() (33)