limit 1000,10 和 limit 10一样快吗?

Opencv4.5.1 微信二维码识别功能 QRCode 编译与使用 C++ 部分参考:https://mp.weixin.qq.com/s/2GZAJAUPHTXFOKDRv-D21Q 一、下载源码 https://github.com/opencv 二、源码编译 ① 在cmake中添加源码编译路径和生成路径,第一次点击configure。 ② 添加contrib路径 第一次configure后,找到OPENCV_EXTRA_MODULES_PATH,将contrib路径添加进来,注意要具体到modules/,继续configure。 .. 阅读详情

刷网站的时候,我们经常会遇到需要分页查询的场景。

比如下图红框里的翻页功能。

图片

我们很容易能联想到可以用mysql实现。

假设我们的建表sql是这样的

图片

mysql建表sql

建表sql大家也不用扣细节,只需要知道id是主键,并且在user_name建了个非主键索引就够了,其他都不重要。

为了实现分页。

很容易联想到下面这样的sql语句。

select * from page order by id limit offset, size;

比如一页有10条数据。

图片

user表数据库原始状态

第一页就是下面这样的sql语句。

select * from page order by id limit 0, 10;

第一百页就是

select * from page order by id limit 990, 10;

那么问题来了。

用这种方式,同样都是拿10条数据,查第一页和第一百页的查询速度是一样的吗?为什么?

两种limit的执行过程

上面的两种查询方式。对应 limit offset, size 和 limit size  两种方式。

而其实 limit size ,相当于  limit 0, size。也就是从0开始取size条数据。

也就是说,两种方式的区别在于offset是否为0。

我们先来看下limit sql的内部执行逻辑。

图片

Mysql架构

mysql内部分为server层和存储引擎层。一般情况下存储引擎都用innodb。

server层有很多模块,其中需要关注的是执行器是用于跟存储引擎打交道的组件。

执行器可以通过调用存储引擎提供的接口,将一行行数据取出,当这些数据完全符合要求(比如满足其他where条件),则会放到结果集中,最后返回给调用mysql的客户端(go、java写的应用程序)。

我们可以对下面的sql先执行下 explain。

explain select * from page order by id limit 0, 10;

可以看到,explain中提示 key 那里,执行的是PRIMARY,也就是走的主键索引。

图片

分页查询offset=0

主键索引本质是一棵B+树,它是放在innodb中的一个数据结构。

我们可以回忆下,B+树大概长这样。

图片

B+树结构

在这个树状结构里,我们需要关注的是,最下面一层节点,也就是叶子结点。而这个叶子结点里放的信息会根据当前的索引是主键还是非主键有所不同。

  • 如果是主键索引,它的叶子节点会存放完整的行数据信息。

  • 如果是非主键索引,那它的叶子节点则会存放主键,如果想获得行数据信息,则需要再跑到主键索引去拿一次数据,这叫回表。

比如执行

select * from page where user_name = "小白10";

会通过非主键索引去查询user_name为"小白10"的数据,然后在叶子结点里找到"小白10"的数据对应的主键为10。

此时回表到主键索引中做查询,最后定位到主键为10的行数据。

图片

回表

但不管是主键还是非主键索引,他们的叶子结点数据都是有序的。比如在主键索引中,这些数据是根据主键id的大小,从小到大,进行排序的。

基于主键索引的limit执行过程

那么回到文章开头的问题里。

当我们去掉explain,执行这条sql。

select * from page order by id limit 0, 10;

上面select后面带的是星号*,也就是要求获得行数据的所有字段信息。

server层会调用innodb的接口,在innodb里的主键索引中获取到第0到10条完整行数据,依次返回给server层,并放到server层的结果集中,返回给客户端。

而当我们把offset搞离谱点,比如执行的是

select * from page order by id limit 6000000, 10;

server层会调用innodb的接口,由于这次的offset=6000000,会在innodb里的主键索引中获取到第0到(6000000 + 10)条完整行数据,返回给server层之后根据offset的值挨个抛弃,最后只留下最后面的size条,也就是10条数据,放到server层的结果集中,返回给客户端。

可以看出,当offset非0时,server层会从引擎层获取到很多无用的数据,而获取的这些无用数据都是要耗时的。

因此,我们就知道了文章开头的问题的答案,mysql查询中 limit 1000,10 会比 limit 10 更慢。原因是 limit 1000,10 会取出1000+10条数据,并抛弃前1000条,这部分耗时更大

那这种case有办法优化吗?

可以看出,当offset非0时,server层会从引擎层获取到很多无用的数据,而当select后面是*号时,就需要拷贝完整的行信息,拷贝完整数据跟只拷贝行数据里的其中一两个列字段耗时是不同的,这就让原本就耗时的操作变得更加离谱。

因为前面的offset条数据最后都是不要的,就算将完整字段都拷贝来了又有什么用呢,所以我们可以将sql语句修改成下面这样。

select * from page  where id >=(select id from page  order by id limit 6000000, 1) order by id limit 10;

上面这条sql语句,里面先执行子查询 select id from page order by id limit 6000000, 1, 这个操作,其实也是将在innodb中的主键索引中获取到6000000+1条数据,然后server层会抛弃前6000000条,只保留最后一条数据的id。

但不同的地方在于,在返回server层的过程中,只会拷贝数据行内的id这一列,而不会拷贝数据行的所有列,当数据量较大时,这部分的耗时还是比较明显的。

在拿到了上面的id之后,假设这个id正好等于6000000,那sql就变成了

select * from page  where id >=(6000000) order by id limit 10;

这样innodb再走一次主键索引,通过B+树快速定位到id=6000000的行数据,时间复杂度是lg(n),然后向后取10条数据。

这样性能确实是提升了,亲测能快一倍左右,属于那种耗时从3s变成1.5s的操作。

这······

属实有些杯水车薪,有点搓,属于没办法中的办法。

基于非主键索引的limit执行过程

上面提到的是主键索引的执行过程,我们再来看下基于非主键索引的limit执行过程。

比如下面的sql语句

select * from page order by user_name  limit 0, 10;

server层会调用innodb的接口,在innodb里的非主键索引中获取到第0条数据对应的主键id后,回表到主键索引中找到对应的完整行数据,然后返回给server层,server层将其放到结果集中,返回给客户端。

而当offset>0时,且offset的值较小时,逻辑也类似,区别在于,offset>0时会丢弃前面的offset条数据。

也就是说非主键索引的limit过程,比主键索引的limit过程,多了个回表的消耗。

但当offset变得非常大时,比如600万,此时执行explain。

图片

非主键索引offset值超大时走全表扫描

可以看到type那一栏显示的是ALL,也就是全表扫描。

这是因为server层的优化器,会在执行器执行sql语句前,判断下哪种执行计划的代价更小。

很明显,优化器在看到非主键索引的600w次回表之后,摇了摇头,还不如全表一条条记录去判断算了,于是选择了全表扫描。

因此,当limit offset过大时,非主键索引查询非常容易变成全表扫描。是真·性能杀手。

这种情况也能通过一些方式去优化。比如

select * from page t1, (select id from page order by user_name limit 6000000, 100) t2  WHERE t1.id = t2.id;

通过select id from page order by user_name limit 6000000, 100。先走innodb层的user_name非主键索引取出id,因为只拿主键id,不需要回表,所以这块性能会稍微快点,在返回server层之后,同样抛弃前600w条数据,保留最后的100个id。然后再用这100个id去跟t1表做id匹配,此时走的是主键索引,将匹配到的100条行数据返回。这样就绕开了之前的600w条数据的回表。

当然,跟上面的case一样,还是没有解决要白拿600w条数据然后抛弃的问题,这也是非常挫的优化。

像这种,当offset变得超大时,比如到了百万千万的量级,问题就突然变得严肃了。

这里就产生了个专门的术语,叫深度分页。

深度分页问题

深度分页问题,是个很恶心的问题,恶心就恶心在,这个问题,它其实无解。

不管你是用mysql还是es,你都只能通过一些手段去"减缓"问题的严重性。

遇到这个问题,我们就该回过头来想想。

为什么我们的代码会产生深度分页问题?

它背后的原始需求是什么,我们可以根据这个做一些规避。

如果你是想取出全表的数据

有些需求是这样的,我们有一张数据库表,但我们希望将这个数据库表里的所有数据取出,异构到es,或者hive里,这时候如果直接执行

select * from page;

这个sql一执行,狗看了都摇头。

因为数据量较大,mysql根本没办法一次性获取到全部数据,妥妥超时报错。

于是不少mysql小白会通过limit offset size分页的形式去分批获取,刚开始都是好的,等慢慢地,哪天数据表变得奇大无比,就有可能出现前面提到的深度分页问题。

这种场景是最好解决的。

我们可以将所有的数据根据id主键进行排序,然后分批次取,将当前批次的最大id作为下次筛选的条件进行查询。

可以看下伪代码

图片

batch获取数据

这个操作,可以通过主键索引,每次定位到id在哪,然后往后遍历100个数据,这样不管是多少万的数据,查询性能都很稳定。

图片

batch分批获取user表

如果是给用户做分页展示

如果深度分页背后的原始需求只是产品经理希望做一个展示页的功能,比如商品展示页,那么我们就应该好好跟产品经理battle一下了。

什么样的翻页,需要翻到10多万以后,这明显是不合理的需求。

是不是可以改一下需求,让它更接近用户的使用行为?

比如,我们在使用谷歌搜索时看到的翻页功能。

图片

一般来说,谷歌搜索基本上都在20页以内,作为一个用户,我就很少会翻到第10页之后。

作为参考。

如果我们要做搜索或筛选类的页面的话,就别用mysql了,用es,并且也需要控制展示的结果数,比如一万以内,这样不至于让分页过深。

如果因为各种原因,必须使用mysql。那同样,也需要控制下返回结果数量,比如数量1k以内。

这样就能勉强支持各种翻页,跳页(比如突然跳到第6页然后再跳到第106页)。

但如果能从产品的形式上就做成不支持跳页会更好,比如只支持上一页或下一页。

图片

上下页的形式

这样我们就可以使用上面提到的start_id方式,采用分批获取,每批数据以start_id为起始位置。这个解法最大的好处是不管翻到多少页,查询速度永远稳定。

听起来很挫?

怎么会呢,把这个功能包装一下。

变成像抖音那样只能上划或下划,专业点,叫瀑布流。

是不是就不挫了?

图片

总结

  • limit offset, size 比 limit size 要慢,且offset的值越大,sql的执行速度越慢。

  • 当offset过大,会引发深度分页问题,目前不管是mysql还是es都没有很好的方法去解决这个问题。只能通过限制查询数量或分批获取的方式进行规避。

  • 遇到深度分页的问题,多思考其原始需求,大部分时候是不应该出现深度分页的场景的,必要时多去影响产品经理。

  • 如果数据量很少,比如1k的量级,且长期不太可能有巨大的增长,还是用limit offset, size 的方案吧,整挺好,能用就行。

参考资料

《MySQL的Limit子句底层原理你不可不知》https://blog.youkuaiyun.com/qq_34115899/article/details/120727513

最后

关于深度分页,如果大家有更好的想法,欢迎评论区说出来。

这道题,是我无能!

告辞!!

论文阅读 AIED 2024 Coding with AI: How Are Tools Like ChatGPT Being Used by Students in Foundational Pro 该论文题为《Coding with AI: How Are Tools Like ChatGPT Being Used by Students in Foundational Programming Courses》,由美国犹他州立大学的 Aashish Ghimire 与 John Edwards 共同撰写,发表于人工智能与教育领域顶级会议。 阅读详情

相关推荐

泰克示波器TDS210改装便携示波器

泰克示波器TDS210改装编写示波器

超级网吧的博客 3080

MySQL查询 limit 1000,10 和limit 10 速度一样快吗?

刷网站的时候,我们经常会遇到需要分页查询的场景。 比如下图红框里的翻页功能。 我们很容易能联想到可以用mysql实现。 假设我们的建表sql是这样的 mysql建表sql 建表sql大家也不用扣细节,只需要知道id是主键,并且在user_name建了个非主键索引就够了,其他都不重要。 为了实现分页。 很容易联想到下面这样的sql语句。 select * from page order by id limit offset, size; 比如一页有10条数据。

m0_69305074的博客 5573

Python | 处理CMIP6 NC数据,以tas为例

各位同学,一般在文章最后一章我们可能会做不同气候情景下变量的未来时空变化特征,类似上图。从cmip6下载的nc数据常需要转换格式、裁剪到研究区和重采样等,本期代码可以解决这类问题。

qq_48539301的博客 1384

SQL 之 limit 基础用法

例2:查询每个年级成绩最好的学生姓名和成绩,按照年级升序排列(较难)

m0_53999934的博客 4549

从Arduino IDE到Atmel Studio:ATmega328P开发的进阶之路

本文探讨了从Arduino IDE转向Atmel Studio进行ATmega328P开发的进阶路径。通过对比两者差异,详细介绍了Atmel Studio的环境配置、寄存器操作思维、烧录方法及高级调试功能,帮助开发者突破Arduino的封装限制,实现对单片机底层硬件的精细控制与性能优化,提升嵌入式开发的专业能力。

weixin_29193259的博客 126

FPGA新手避坑指南:手把手教你搞定RTL8211千兆网PHY的时序配置(附Verilog代码)

本文详细解析了FPGA与RTL8211千兆网PHY芯片的时序配置问题,重点介绍了TXDLY/RXDLY引脚设置、FPGA发送端和接收端的Verilog实现,以及调试与验证的完整流程。通过硬件电路设计和代码示例,帮助开发者解决网络连接不稳定、丢包等常见问题,提升千兆网通信的稳定性。

weixin_28732953的博客 542

limit 10和limit 10000 10效率相同吗

先说结论:不相同,差异很大。对比Query_ID为57和64的语句发现执行时间limit 10比limit 10000,10效率高了10倍。什么原因呢?这就要从limit的底层原理开始讲起。请继续往下看。

zyjzyjjyzjyz的博客 2521

Transformer在CV里太耗算力?手把手拆解Restormer的MDTA与GDFN模块

本文深度解析了CVPR2022最佳论文提名作品Restormer的创新模块MDTA与GDFN,有效解决了Transformer在计算机视觉领域的高计算复杂度问题。通过通道注意力降维和门控前馈网络设计,Restormer在图像恢复重建任务中显著降低计算量,同时保持高性能,为实时图像处理提供了可行方案。

weixin_30258901的博客 446

HiveSql中limit10的坑——对大数据量的表查询加group by

一般查询hive表中某个字段是否存在某个值,会使用如下查询语句 select * from 表名 where dt=XXXX and 字段 like '%某个值%' limit 10; 这种比较适合hive表数据量较小的情况,出现limit10,hive会默认判断此表数据量不大,只开启一个map进行查询, 如果对于大表,比如好几百G上T的数据量,这么大的数据量只开一个map一方面查询慢,另一方面,因为数据量太大容易把机器跑崩。 采用以下方式即可,加上group by,然后就会依据hive表的文件

攻城狮Kevin 7564

给麒麟KylinOS服务器加把锁:手把手配置符合等保要求的密码强度策略

本文详细介绍了如何在麒麟KylinOS服务器上配置符合等保要求的密码强度策略,包括pwquality.conf和login.defs的核心参数设置、等保合规的进阶配置技巧以及企业环境中的平衡艺术。通过实战案例和测试方法,帮助管理员构建坚固的密码防线,确保系统安全。

weixin_33749242的博客 419

vCenter6.7证书过期导致503报错的全面修复指南:从STS证书更新到SSL信任修复

本文详细解析了VMware vCenter 6.7因STS证书过期导致503服务不可用错误的根本原因,并提供了从诊断、更新STS证书到修复SSL信任链的完整解决方案。通过命令行工具检查证书状态,使用官方脚本更新过期STS证书,并利用lsdoctor工具修复深层SSL信任问题,最终指导用户使用certificate-manager彻底重置所有证书,帮助管理员快速恢复vCenter服务。

pz890123的博客 1294

limit(1000,10)和limit10查询性能差别大吗

limit(1000,10)和limit10查询性能差别大吗,分析为什么

weixin_43735471的博客 1042

PLC模糊控制模糊PID(梯形图实现+算法分析)

博途PLC的模糊PID控制详细内容请查看下面的博客文章:Matlab仿真+博途PLC模糊PID控制完整SCL源代码参考(带模糊和普通PID切换功能)_博途怎么实现模糊pid_RXXW_Dor的博客-优快云博客模糊PID的其它相关数学基础,理论知识大家可以参看专栏的其它文章,这里不再赘述,本文就双容水箱的模糊PID问题做详细讲解(包括所有源代码和模糊规则设置参数)。

RXXW_Dor的博客 5885

深分页问题,mysql查询 limit 1000,10 和limit 10 一样快吗?

比limit size要慢,且offset的值越大,sql的执行速度越慢。当offset过大,会引发深度分页问题,目前不管是mysql还是es都没有很好的方法去解决这个问题。只能通过限制查询数量或分批获取的方式进行规避。遇到深度分页的问题,多思考其原始需求,大部分时候是不应该出现深度分页的场景的,必要时多去影响产品经理。如果数据量很少,比如1k的量级,且长期不太可能有巨大的增长,还是用的方案吧,整挺好,能用就行。...

LoveSummer 3万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

mysql查询 limit 1000,10 和limit 10 一样快么,如何优化?

mysql查询 limit 1000,10 和limit 10 一样快么,如何优化?

Boy_Martin的博客 2120

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

MySQL查询 limit 1000,10 和limit 10 速度一样快吗?如果我要分页,我该怎么办?

比limit size要慢,且offset的值越大,sql的执行速度越慢。当offset过大,会引发深度分页问题,目前不管是mysql还是es都没有很好的方法去解决这个问题。只能通过限制查询数量或分批获取的方式进行规避。遇到深度分页的问题,多思考其原始需求,大部分时候是不应该出现深度分页的场景的,必要时多去影响产品经理。如果数据量很少,比如1k的量级,且长期不太可能有巨大的增长,还是用的方案吧,整挺好,能用就行。

weixin_62421895的博客 895

mysql查询 limit 1000,10 和limit 10 一样快吗?

刷网站的时候,我们经常会遇到需要分页查询的场景。比如下图红框里的翻页功能。我们很容易能联想到可以用mysql实现。假设我们的建表sql是这样的mysql建表sql建表sql大家也不用扣细节,只需要知道id是主键,并且在user_name建了个非主键索引就够了,其他都不重要。为了实现分页。很容易联想到下面这样的sql语句。select * from page order by id l

知识分享官 306

MySQL 查询 limit 1000,10 和 limit 10 速度一样快吗? 深度分页如何破解

刷网站的时候,我们经常会遇到需要分页查询的场景。比如下图红框里的翻页功能。我们很容易能联想到可以用mysql实现。假设我们的建表sql是这样的mysql建表sql建表sql大家也不用扣细节,只需要知道id是主键,并且在user_name建了个非主键索引就够了,其他都不重要。为了实现分页。很容易联想到下面这样的sql语句。 比如一页有10条数据。user表数据库原始状态第一页就是下面这样的sql语句。 第一百页就是 那么问题来了。用这种方式,同样都是拿10条数据,查第一页和第一百页的查询速度是一样

hahazz233的博客 829

mysql查询 limit 1000,10 和limit 10 速度一样快吗?如果我要分页,我该怎么办?

比limit size要慢,且offset的值越大,sql的执行速度越慢。当offset过大,会引发深度分页问题,目前不管是mysql还是es都没有很好的方法去解决这个问题。只能通过限制查询数量或分批获取的方式进行规避。遇到深度分页的问题,多思考其原始需求,大部分时候是不应该出现深度分页的场景的,必要时多去影响产品经理。如果数据量很少,比如1k的量级,且长期不太可能有巨大的增长,还是用的方案吧,整挺好,能用就行。

cxytony的博客 375

mysql查询速度 limit 1000,10 和limit 10 一样快吗?

刷网站的时候,我们经常会遇到需要分页查询的场景。比如下图红框里的翻页功能。我们很容易能联想到可以用mysql实现。假设我们的建表sql是这样的mysql建表sql建表sql大家也不用扣细节,只需要知道id是主键,并且在user_name建了个非主键索引就够了,其他都不重要。为了实现分页。很容易联想到下面这样的sql语句。select * from page order by id l

jjc4261的博客 630

阿里二面:mysql查询 limit 1000,10 和limit 10 一样快吗?

刷网站的时候,我们经常会遇到需要分页查询的场景。比如下图红框里的翻页功能。我们很容易能联想到可以用mysql实现。假设我们的建表sql是这样的mysql建表sql建表sql大家也不用扣细节,只需要知道id是主键,并且在user_name建了个非主键索引就够了,其他都不重要。为了实现分页。很容易联想到下面这样的sql语句。select * from page order by id l

chenxuyuana的博客 262
上一篇: 写出“屎山”代码的12个技巧 ,一定得会!
下一篇: 一个 List.of 引发的“血案”
IT界那些事儿
博客等级 码龄6年 2万+粉丝 22原创
评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值