Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >别再用 offset 和 limit 分页了,性能太差!

别再用 offset 和 limit 分页了,性能太差!

作者头像
良月柒
发布于 2023-12-13 04:41:03
发布于 2023-12-13 04:41:03
41600
代码可运行
举报
运行总次数:0
代码可运行

程序员的成长之路

互联网/程序员/技术/资料共享

关注

阅读本文大概需要 3.5 分钟。

来自:toutiao.com/i6860655404431442444

  • 1、OFFSET 和 LIMIT 有什么问题?
  • 2、替代方案

旁白君:主要去理解 offset 为什么会在大数据量下的查询带来性能问题? 思考完后,可以在思考下,如果分库分表,你会这么去分页呢?

不需要担心数据库性能优化问题的日子已经一去不复返了。

随着时代的进步,随着野心勃勃的企业想要变成下一个 Facebook,随着为机器学习预测收集尽可能多数据的想法的出现,作为开发人员,我们要不断地打磨我们的 API,让它们提供可靠和有效的端点,从而毫不费力地浏览海量数据。

如果你做过后台开发或数据库架构,你可能是这么分页的:

图片

如果你真的是这么分页,那么我不得不抱歉地说,你这样做是错的。

你不以为然?没关系。Slack、Shopify 和 Mixmax 这些公司都在用我们今天将要讨论的方式进行分页。

我想你很难找出一个不使用 OFFSET 和 LIMIT 进行数据库分页的人。对于简单的小型应用程序和数据量不是很大的场景,这种方式还是能够“应付”的。

如果你想从头开始构建一个可靠且高效的系统,在一开始就要把它做好。

今天我们将探讨已经被广泛使用的分页方式存在的问题,以及如何实现高性能分页。

1、OFFSET 和 LIMIT 有什么问题?

正如前面段落所说的那样,OFFSET 和 LIMIT 对于数据量少的项目来说是没有问题的。

但是,当数据库里的数据量超过服务器内存能够存储的能力,并且需要对所有数据进行分页,问题就会出现。

为了实现分页,每次收到分页请求时,数据库都需要进行低效的全表扫描。

什么是全表扫描?全表扫描 (又称顺序扫描) 就是在数据库中进行逐行扫描,顺序读取表中的每一行记录,然后检查各个列是否符合查询条件。这种扫描是已知最慢的,因为需要进行大量的磁盘 I/O,而且从磁盘到内存的传输开销也很大。

这意味着,如果你有 1 亿个用户,OFFSET 是 5 千万,那么它需要获取所有这些记录 (包括那么多根本不需要的数据),将它们放入内存,然后获取 LIMIT 指定的 20 条结果。

也就是说,为了获取一页的数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
10万行中的第5万行到第5万零20

需要先获取 5 万行。这么做是多么低效?

如果你不相信,可以看看这个例子:

https://www.db-fiddle.com/f/3JSpBxVgcqL3W2AzfRNCyq/1?ref=hackernoon.com

左边的 Schema SQL 将插入 10 万行数据,右边有一个性能很差的查询和一个较好的解决方案。只需单击顶部的 Run,就可以比较它们的执行时间。第一个查询的运行时间至少是第二个查询的 30 倍。

数据越多,情况就越糟。看看我对 10 万行数据进行的 PoC。

https://github.com/IvoPereira/Efficient-Pagination-SQL-PoC?ref=hackernoon.com

现在你应该知道这背后都发生了什么:OFFSET 越高,查询时间就越长。

2、替代方案

你应该这样做:

图片

这是一种基于指针的分页。

你要在本地保存上一次接收到的主键 (通常是一个 ID) 和 LIMIT,而不是 OFFSET 和 LIMIT,那么每一次的查询可能都与此类似。

为什么?因为通过显式告知数据库最新行,数据库就确切地知道从哪里开始搜索(基于有效的索引),而不需要考虑目标范围之外的记录。

比较这个查询:

图片

和优化的版本:

图片

返回同样的结果,第一个查询使用了 12.80 秒,而第二个仅用了 0.01 秒。

要使用这种基于游标的分页,需要有一个惟一的序列字段 (或多个),比如惟一的整数 ID 或时间戳,但在某些特定情况下可能无法满足这个条件。

我的建议是,不管怎样都要考虑每种解决方案的优缺点,以及需要执行哪种查询。

如果需要基于大量数据做查询操作,Rick James 的文章提供了更深入的指导。

http://mysql.rjweb.org/doc.php/lists

如果我们的表没有主键,比如是具有多对多关系的表,那么就使用传统的 OFFSET/LIMIT 方式,只是这样做存在潜在的慢查询问题。我建议在需要分页的表中使用自动递增的主键,即使只是为了分页。

<END>

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper......等技术栈!
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的成长之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
别再用OFFSET和LIMIT分页了
随着时代的进步,随着野心勃勃的企业想要变成下一个 Facebook,随着为机器学习预测收集尽可能多数据的想法的出现,作为开发人员,我们要不断地打磨我们的 API,让它们提供可靠和有效的端点,从而毫不费力地浏览海量数据。
深度学习与Python
2020/08/17
1.1K0
求求你不要再用offset和limit了
随着时代的发展,每个新企业家都希望建立下一个Facebook,并结合收集每个可能的数据点以提供更好的机器学习预测的心态,作为开发人员,我们需要比以往更好地准备我们的API,以提供可靠,高效的端点,应该能够毫不费力地浏览大量数据。
JavaPub
2021/01/11
1.3K1
别再用 offset 和 limit 分页了,性能太差!
随着时代的进步,随着野心勃勃的企业想要变成下一个 Facebook,随着为机器学习预测收集尽可能多数据的想法的出现,作为开发人员,我们要不断地打磨我们的 API,让它们提供可靠和有效的端点,从而毫不费力地浏览海量数据。
Java团长
2022/08/12
5080
别再用 offset 和 limit 分页了,性能太差!
LIMIT和OFFSET分页性能差!今天来介绍如何高性能分页
OFFSET 和 LIMIT 对于数据量少的项目来说是没有问题的,但是,当数据库里的数据量超过服务器内存能够存储的能力,并且需要对所有数据进行分页,问题就会出现,为了实现分页,每次收到分页请求时,数据库都需要进行低效的全表遍历。
GreatSQL社区
2023/02/23
1.7K0
mysql查询 limit 1000,10 和limit 10 速度一样快吗?如果我要分页,我该怎么办?
建表sql大家也不用扣细节,只需要知道id是主键,并且在user_name建了个非主键索引就够了,其他都不重要。
小白debug
2022/06/20
1.7K0
mysql查询 limit 1000,10 和limit 10 速度一样快吗?如果我要分页,我该怎么办?
MySQL 案例:Limit 分页查询优化
在各类系统的表格类信息展示的功能中,经常会用到“翻页”这个操作,在页面上每次只展示有限的数据,需要看其他数据的时候则像翻书一样翻到后面的“页”。在 MySQL 支持的 SQL 语法中对此有特殊的支持,开发人员在实现这类功能的时候很方便:
王文安@DBA
2020/07/28
3.7K0
MySQL 案例:Limit 分页查询优化
灵魂两问:MySQL分页有什么性能问题?怎么优化?
在这种建表语句中不用过度注重细节,只需要知道 id 是主键,并且在user_name建了一个非主键的索引就行了。
xiao李
2024/02/03
8170
灵魂两问:MySQL分页有什么性能问题?怎么优化?
分页查询 offset 和 limit 和 limit 的区别
select * from table limit 0,1000; select * from table limit 1000 offset 0;
袁新栋-jeff.yuan
2020/08/26
3.1K0
MySQL深分页,limit 100000,10 优化
我们日常做分页需求时,一般会用limit实现,但是当偏移量特别大的时候,查询效率就变得低下。本文将分4个方案,讨论如何优化MySQL百万数据的深分页问题.
寻求出路的程序媛
2024/06/05
8290
MySQL深分页,limit 100000,10 优化
关于mysql limit offset的一点优化
举个例子select * from test where val=4 limit 300000,5;的查询过程:
MickyInvQ
2020/09/27
9.4K0
关于mysql limit offset的一点优化
MySQL分页查询详解:优化大数据集的LIMIT和OFFSET
最近在工作中,我们遇到了一个需求,甲方要求直接从数据库导出一个业务模块中所有使用中的工单信息。为了实现这一目标,我编写了一条SQL查询语句,并请求DBA协助导出数据。尽管工单数量并不多,只有3000多条,但每个工单都包含了大量的信息。DBA进行了多次导出操作,不幸的是,每次尝试导出都导致了操作平台的卡顿和无响应。
修己xj
2023/09/02
8330
MySQL分页查询详解:优化大数据集的LIMIT和OFFSET
API 分页探讨:offset 来分页真的有效率?
对于设计和实现 API 来说,当结果集包含成千上万条记录时,返回一个查询的所有结果可能是一个挑战,它给服务器、客户端和网络带来了不必要的压力,于是就有了分页的功能。
二哥聊运营工具
2021/12/17
1.4K0
API 分页探讨:offset 来分页真的有效率?
MySQL分页性能优化指南
一道面试的问题,当MySQL表中有数据量很大的时候如何做分页。。。。当时只知道在数据量很大的时候可以分表,但不知道不分表时可以怎么做。。。。唉,谁让代理商就那么几条数据,一个简单的limit,offset就完全hold住了(捂脸)。。。 很多应用往往只展示最新或最热门的几条记录,但为了旧记录仍然可访问,所以就需要个分页的导航栏。然而,如何通过MySQL更好的实现分页,始终是比较令人头疼的问题。虽然没有拿来就能用的解决办法,但了解数据库的底层或多或少有助于优化分页查询。 我们先从一个常用但性能很差的查询来看一
用户1667431
2018/04/18
1.2K0
一个案例彻底弄懂如何正确使用 mysql inndb 联合索引
查看当时的监控情况 cpu 使用率是超过了100%,show processlist看到很多类似的查询都是处于create sort index的状态。
用户7657330
2020/08/14
4640
一个案例彻底弄懂如何正确使用 mysql inndb 联合索引
【mysql】limit实现分页
分页 1. 背景: 背景1:查询返回的记录太多了,查看起来很不方便,怎么样能够实现分页查询呢? 背景2:表里有 4 条数据,如果只想要显示第 2、3 条数据怎么办呢? 2. 实现规则 分页原理 所谓分页显示,就是将数据库中的结果集,一段一段显示出来需要的条件。 MySQL中使用 LIMIT 实现分页 格式: LIMIT 位置偏移量, 行数 第一个“位置偏移量”参数指示MySQL从哪一行开始显示,是一个可选参数,如果不指定“位置偏移量”,将会从表中的第一条记录开始(第一条记录的位置偏移量是0,第二条记
兮动人
2022/03/04
3.9K0
Mysql的limit用法
Mysql的limit用法
Java架构师必看
2021/09/23
2.8K0
Mysql的limit用法
半夜被慢查询告警吵醒,limit深度分页的坑
梅雨季,闷热的夜,令人窒息,窗外一道道闪电划破漆黑的夜幕,小猫塞着耳机听着恐怖小说,辗转反侧,终于睡意来了,然而挨千刀的手机早不振晚不振,偏偏这个时候振动了一下,一个激灵,没有按捺住对内容的好奇,点开了短信,卧槽?告警信息,原来是负责的服务出现慢查询了。小猫想起来,今天在下班之前上线了一个版本,由于新增了一个业务字段,所以小猫写了相关的刷数据的接口,在下班之前调用开始刷历史数据。
程序员老猫
2024/07/08
1160
半夜被慢查询告警吵醒,limit深度分页的坑
千万级数据深分页查询SQL性能优化实践
Tech 导读 分页查询在数据库中是一种很常见的应用场景,一般都可以使用limit语句快速实现。但是随着表数据的增长,limit查询性能也会越来越慢。
京东技术
2023/11/13
6970
千万级数据深分页查询SQL性能优化实践
给你讲讲五年前工作遇到的,海量数据分页场景(limit,offset)为什么会慢
原文链接:http://t.cn/AidABz08
业余草
2019/12/03
6610
从 12s 到 200ms,MySQL 两千万订单数据 6 种深度分页优化全解析
那晚,大约晚上 11 点,我与 Chaya 在丽江的洱海酒店享受两人世界的快乐,电商平台的运维大群突然炸开了锅。
码哥字节
2025/02/25
3630
从 12s 到 200ms,MySQL 两千万订单数据 6 种深度分页优化全解析
推荐阅读
相关推荐
别再用OFFSET和LIMIT分页了
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验