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

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 在前端页面显示,为了避免一次性展示全量数据,通过上下翻页或指定页码的方式查看部分数据,就像翻书一样,这就利用了 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 风险,建议把子查询仅作为应急过渡方案。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
JavaScript 关系型数据库 MySQL
❤Nodejs 第六章(操作本地数据库前置知识优化)
【4月更文挑战第6天】本文介绍了Node.js操作本地数据库的前置配置和优化,包括处理接口跨域的CORS中间件,以及解析请求数据的body-parser、cookie-parser和multer。还讲解了与MySQL数据库交互的两种方式:`createPool`(适用于高并发,通过连接池管理连接)和`createConnection`(适用于低负载)。
20 0
|
24天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
|
1月前
|
SQL 缓存 PHP
PHP技术探究:优化数据库查询效率的实用方法
本文将深入探讨PHP中优化数据库查询效率的实用方法,包括索引优化、SQL语句优化以及缓存机制的应用。通过合理的优化策略和技巧,可以显著提升系统性能,提高用户体验,是PHP开发者不容忽视的重要议题。
|
1月前
|
SQL 存储 JSON
阿里云数据库 SelectDB 内核 Apache Doris 2.1.0 版本发布:开箱盲测性能大幅优化,复杂查询性能提升 100%
亲爱的社区小伙伴们,Apache Doris 2.1.0 版本已于 2024 年 3 月 8 日正式发布,新版本开箱盲测性能大幅优化,在复杂查询性能方面提升100%,新增Arrow Flight接口加速数据读取千倍,支持半结构化数据类型与分析函数。异步多表物化视图优化查询并助力仓库分层建模。引入自增列、自动分区等存储优化,提升实时写入效率。Workload Group 资源隔离强化及运行时监控功能升级,保障多负载场景下的稳定性。新版本已经上线,欢迎大家下载使用!
阿里云数据库 SelectDB 内核 Apache Doris 2.1.0 版本发布:开箱盲测性能大幅优化,复杂查询性能提升 100%
|
24天前
|
存储 关系型数据库 MySQL
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
|
3天前
|
存储 缓存 关系型数据库
掌握MySQL数据库这些优化技巧,事半功倍!
掌握MySQL数据库这些优化技巧,事半功倍!
|
4天前
|
缓存 关系型数据库 MySQL
MySQL数据库优化技巧:提升性能的关键策略
索引是提高查询效率的关键。根据查询频率和条件,创建合适的索引能够加快查询速度。但要注意,过多的索引可能会增加写操作的开销,因此需要权衡。
|
12天前
|
SQL 缓存 Java
Java数据库连接池:优化数据库访问性能
【4月更文挑战第16天】本文探讨了Java数据库连接池的重要性和优势,它能减少延迟、提高效率并增强系统的可伸缩性和稳定性。通过选择如Apache DBCP、C3P0或HikariCP等连接池技术,并进行正确配置和集成,开发者可以优化数据库访问性能。此外,批处理、缓存、索引优化和SQL调整也是提升性能的有效手段。掌握数据库连接池的使用是优化Java企业级应用的关键。
|
13天前
|
SQL 关系型数据库 数据库
【后端面经】【数据库与MySQL】SQL优化:如何发现SQL中的问题?
【4月更文挑战第12天】数据库优化涉及硬件升级、操作系统调整、服务器/引擎优化和SQL优化。SQL优化目标是减少磁盘IO和内存/CPU消耗。`EXPLAIN`命令用于检查SQL执行计划,关注`type`、`possible_keys`、`key`、`rows`和`filtered`字段。设计索引时考虑外键、频繁出现在`where`、`order by`和关联查询中的列,以及区分度高的列。大数据表改结构需谨慎,可能需要停机、低峰期变更或新建表。面试中应准备SQL优化案例,如覆盖索引、优化`order by`、`count`和索引提示。优化分页查询时避免大偏移量,可利用上一批的最大ID进行限制。
39 3
|
25天前
|
缓存 监控 数据库
优化数据库查询性能的八大技巧
在今天的互联网时代,数据库是许多应用程序的核心组件之一。优化数据库查询性能是提升应用程序整体性能的关键。本文介绍了八种有效的技巧,帮助开发人员提高数据库查询性能,从而提升应用程序的响应速度和用户体验。

热门文章

最新文章