数据库深分页介绍及优化方案

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 在前端页面显示,为了避免一次性展示全量数据,通过上下翻页或指定页码的方式查看部分数据,就像翻书一样,这就利用了 MySQL 的分页查询。

在前端页面显示,为了避免一次性展示全量数据,通过上下翻页或指定页码的方式查看部分数据,就像翻书一样,这就利用了 MySQL 的分页查询。

一、MySQL 的深分页
查询偏移量过大的分页会导致数据库获取数据性能低下,以如下 SQL 为例:

SELECT * FROM t_order ORDER BY id LIMIT 1000000, 10
这句 SQL 会使得 MySQL 在无法利用索引的情况下跳过 1000000 条记录后,再获取 10 条记录,其性能可想而知。这种查询偏移量过大的场景我们称为深分页。

MySQL 的深分页会带来性能下降等问题,而这个问题在分布式数据库场景下,会变得更加复杂。

二、分布式数据库的深分页
弹性数据库 JED 可以简单理解成分布式的 MySQL 数据库,这里以 JED 为例,介绍下大多数分布式数据库是如何做分页查询的。

2.1 弹性数据库的分页实现
以下图的例子,我们来介绍多分片数据库如何执行分页查询。t_order 表以 id 作为主键以 t_col1 作为分片键,数据分布如下:



为了获取 t_order 表第 2 条之后的两条数据,执行 SQL:

SELECT * FROM t_order ORDER BY id LIMIT 2, 2
假如只是简单的把 SQL 下推到每个分片的 MySQL 实例执行,再在内存中对返回结果进行聚合排序处理,会是什么效果呢?

分片 1 返回结果 {(id : 4, t_col1 : "a"), (id : 10, t_col1 : "a")};

分片 2 返回结果 {(id : 7, t_col1 : "b"), (id : 8, t_col1 : "b")};

内存排序计算后,将结果 {(id : 4, t_col1 : "a"),(id : 7, t_col1 : "b")} 返回,显然这是一个错误的结果。为了得到正确的结果,需要每个分片都获取前 4 条(2+2)数据,之后在内存中进行排序后分页。因此,每个分片执行的 SQL 改写为:

SELECT * FROM t_order ORDER BY id LIMIT 0, 4
再将返回的结果集在内存排序后,取第 2 条之后的两条数据 {(id : 4, t_col1 : "a"),(id : 5, t_col1 : "b")} 返回用户。

2.2 深分页存在的问题
由于分布式场景下,分页语句会被放大。而这个问题,在执行深分页 SQL 时(查询偏移量过大),更加严重。深分页会导致数据库性能急剧下降,并且占用大量的 CPU、内存资源用于聚合排序运算。

当执行以下 SQL,获取 1000000 之后的 10 条数据:

SELECT * FROM t_order ORDER BY id LIMIT 1000000, 10
在多分片场景下,为了保证数据的正确性,SQL 会改写为:

SELECT FROM t_order ORDER BY id LIMIT 0, 1000010
将改写后的 SQL 发送至每一个分片执行,并将结果集返回,对结果集汇总处理后,把排序后的 10 条记录返回给用户。可以发现原 SQL 仅需要传输 10 条记录至客户端,而改写之后的 SQL 则会传输 1000010
2 的记录至客户端,这将极大增大了 OOM 风险。

三、VtDriver 的深分页优化
3.1 SQL 下推
VtDriver 对查询条件中带有分片键,仅落至单一分片的查询进行进一步优化。 落至单分片查询的请求并不需要改写 SQL 也可以保证记录的正确性,因此在此种情况下,VtDriver 并未进行 SQL 改写,从而达到节省资源的效果。

3.2 流式处理
应用侧主动开启流式查询功能。开启流式查询后,采用流式处理 + 归并排序的方式来避免内存的过量占用。由于 SQL 改写不可避免的占用了额外的带宽,但并不会导致内存暴涨。 与直觉不同,大多数人认为 VtDriver 会将 1000010 * 2 记录全部加载至内存,进而占用大量内存而导致内存溢出。 但由于每个结果集的记录是有序的,因此 VtDriver 每次比较仅获取各个分片的当前结果集记录,驻留在内存中的记录仅为当前路由到的分片的结果集的当前游标指向而已。 对于本身即有序的待排序对象,采用归并排序,将会进一步降低性能损耗。

3.3 深分页自动转为流式查询
针对深度分页,VtDriver 提供了根据深度分页临界值,自动开启流式查询的方式。

应用可通过 deepPaginationThreshold 参数,设置深度分页临界值。比如 limit N,M,当 N>deepPaginationThreshold 设置的值时,会转为流式查询。

四、深分页的优化建议
可以看到,即便 VtDriver 对于深分页进行了优化,但是深分页的使用场景还是会给应用带来了很大的压力。用户通过优化 SQL 才可以从根本上解决问题。

4.1 范围查询
当可以保证 ID 的连续性时,用户根据 ID 范围进行分页是比较好的解决方案:

SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER BY id
或通过记录上次查询结果的最后一条记录的 ID 进行下一页的查询:

SELECT * FROM t_order WHERE id > 100000 LIMIT 10
4.2 子查询
把查询条件,转移回到主键索引。由于子查询中只获取主键列对应的值,可以一定程度上降低应用 OOM 风险。

改写后的 SQL 为(id 为表 t_order 的主键):

SELECT * FROM t_order WHERE id >= (SELECT id FROM t_order limit 1000000, 1) LIMIT 10;
数据量过大时,客户端仍有 OOM 风险,建议把子查询仅作为应急过渡方案。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
4月前
|
关系型数据库 MySQL 数据库连接
Django数据库配置避坑指南:从初始化到生产环境的实战优化
本文介绍了Django数据库配置与初始化实战,涵盖MySQL等主流数据库的配置方法及常见问题处理。内容包括数据库连接设置、驱动安装、配置检查、数据表生成、初始数据导入导出,并提供真实项目部署场景的操作步骤与示例代码,适用于开发、测试及生产环境搭建。
144 1
|
18天前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
215 4
|
7月前
|
SQL 关系型数据库 数据库
【YashanDB知识库】OM仲裁节点故障后手工切换方案和yasom仲裁重新部署后重新纳管数据库集群方案
本文介绍了主备数据库集群的部署、OM仲裁故障切换及重新纳管的全过程。首先通过解压软件包并调整安装参数完成数据库集群部署,接着说明了在OM仲裁故障时的手动切换方案,包括关闭自动切换开关、登录备节点执行切换命令。最后详细描述了搭建新的yasom仲裁节点以重新纳管数据库集群的步骤,如生成配置文件、初始化进程、执行托管命令等,确保新旧系统无缝衔接,保障数据服务稳定性。
|
3月前
|
机器学习/深度学习 SQL 运维
数据库出问题还靠猜?教你一招用机器学习优化运维,稳得一批!
数据库出问题还靠猜?教你一招用机器学习优化运维,稳得一批!
106 4
|
7月前
|
SQL 关系型数据库 MySQL
如何优化SQL查询以提高数据库性能?
这篇文章以生动的比喻介绍了优化SQL查询的重要性及方法。它首先将未优化的SQL查询比作在自助餐厅贪多嚼不烂的行为,强调了只获取必要数据的必要性。接着,文章详细讲解了四种优化策略:**精简选择**(避免使用`SELECT *`)、**专业筛选**(利用`WHERE`缩小范围)、**高效联接**(索引和限制数据量)以及**使用索引**(加速搜索)。此外,还探讨了如何避免N+1查询问题、使用分页限制结果、理解执行计划以及定期维护数据库健康。通过这些技巧,可以显著提升数据库性能,让查询更高效流畅。
|
7月前
|
消息中间件 缓存 NoSQL
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
|
7月前
|
关系型数据库 Shell 网络安全
定期备份数据库:基于 Shell 脚本的自动化方案
本篇文章分享一个简单的 Shell 脚本,用于定期备份 MySQL 数据库,并自动将备份传输到远程服务器,帮助防止数据丢失。
|
8月前
|
关系型数据库 数据库 数据安全/隐私保护
云数据库实战:基于阿里云RDS的Python应用开发与优化
在互联网时代,数据驱动的应用已成为企业竞争力的核心。阿里云RDS为开发者提供稳定高效的数据库托管服务,支持多种数据库引擎,具备自动化管理、高可用性和弹性扩展等优势。本文通过Python应用案例,从零开始搭建基于阿里云RDS的数据库应用,详细演示连接、CRUD操作及性能优化与安全管理实践,帮助读者快速上手并提升应用性能。
|
8月前
|
SQL 存储 关系型数据库
【SQL技术】不同数据库引擎 SQL 优化方案剖析
不同数据库系统(MySQL、PostgreSQL、Doris、Hive)的SQL优化策略。存储引擎特点、SQL执行流程及常见操作(如条件查询、排序、聚合函数)的优化方法。针对各数据库,索引使用、分区裁剪、谓词下推等技术,并提供了具体的SQL示例。通用的SQL调优技巧,如避免使用`COUNT(DISTINCT)`、减少小文件问题、慎重使用`SELECT *`等。通过合理选择和应用这些优化策略,可以显著提升数据库查询性能和系统稳定性。
274 9

热门文章

最新文章