一、问题复现

在实际的软件系统开发过程中,随着使用的用户群体越来越多,表数据也会随着时间的推移,单表的数据量会越来越大。

以订单表为例,假如每天的订单量在 4 万左右,那么一个月的订单量就是 120 多万,一年就是 1400 多万,随着年数的增加和单日下单量的增加,订单表的数据量会越来越庞大,订单数据的查询不会像最初那样简单快速,如果查询关键字段没有走索引,会直接影响到用户体验,甚至会影响到服务是否能正常运行

下面我以某个电商系统的客户表为例,数据库是 Mysql,数据体量在 100 万以上,详细介绍分页查询下,不同阶段的查询效率情况(订单表的情况也是类似的,只不过它的数据体量比客户表更大)。

下面我们一起来测试一下,每次查询客户表时最多返回 100 条数据,不同的起始下,数据库查询性能的差异。

  • 当起点位置在 0 的时候,仅耗时:18 ms

  • 当起点位置在 1000 的时候,仅耗时:23 ms

  • 当起点位置在 10000 的时候,仅耗时:54 ms

  • 当起点位置在 100000 的时候,仅耗时:268 ms

  • 当起点位置在 500000 的时候,仅耗时:1.16 s

  • 当起点位置在 1000000 的时候,仅耗时:2.35 s

可以非常清晰的看出,随着起点位置越大,分页查询效率成倍的下降,当起点位置在 1000000 以上的时候,对于百万级数据体量的单表,查询耗时基本上以秒为单位。

而事实上,一般查询耗时超过 1 秒的 SQL 都被称为慢 SQL,有的公司运维组要求的可能更加严格,比如小编我所在的公司,如果 SQL 的执行耗时超过 0.2s,也被称为慢 SQL,必须在限定的时间内尽快优化,不然可能会影响服务的正常运行和用户体验

对于千万级的单表数据查询,小编我刚刚也使用了一下分页查询,起点位置在 10000000,也截图给大家看看,查询耗时结果:39 秒

没有接触过这么大数据体量的同学,可能多少对这种查询结果会感到吃惊,事实上,这还只是数据库层面的耗时,还没有算后端服务的处理链路时间,以及返回给前端的数据渲染时间,以百万级的单表查询为例,如果数据库查询耗时 1 秒,再经过后端的数据封装处理,前端的数据渲染处理,以及网络传输时间,没有异常的情况下,差不多在 3~4 秒之间,可能有些同学对这个请求时长数值还不太敏感。

据互联网软件用户体验报告,当平均请求耗时在1秒之内,用户体验是最佳的,此时的软件也是用户留存度最高的;2 秒之内,还勉强过的去,用户能接受;当超过 3 秒,体验会稍差;超过 5 秒,基本上会卸载当前软件。

有的公司为了提升用户体验,会严格控制请求时长,当请求时长超过 3 秒,自动放弃请求,从而倒逼技术优化调整 SQL 语句查询逻辑,甚至调整后端整体架构,比如引入缓存中间件 redis,搜索引擎 elasticSearch 等等。

继续回到我们本文所需要探讨的问题,当单表数据量到达百万级的时候,查询效率急剧下降,如何优化提升呢

二、解决方案

下面我们一起来看看具体的解决办法。

2.1、方案一:查询的时候,只返回主键 ID

我们继续回到上文给大家介绍的客户表查询,将select *改成select id,简化返回的字段,我们再来观察一下查询耗时。

  • 当起点位置在 100000 的时候,仅耗时:73 ms

  • 当起点位置在 500000 的时候,仅耗时:274 ms

  • 当起点位置在 1000000 的时候,仅耗时:471 ms

可以很清晰的看到,通过简化返回的字段,可以很显著的成倍提升查询效率

实际的操作思路就是先通过分页查询满足条件的主键 ID,然后通过主键 ID 查询部分数据,可以显著提升查询效果。

-- 先分页查询满足条件的主键ID
select id from bizuser order by id limit 100000,10;-- 再通过分页查询返回的ID,批量查询数据
select * from bizuser where id in (1,2,3,4,.....);

2.2、方案二:查询的时候,通过主键 ID 过滤

这种方案有一个要求就是主键ID,必须是数字类型,实践的思路就是取上一次查询结果的 ID 最大值,作为过滤条件,而且排序字段必须是主键 ID,不然分页排序顺序会错乱

  • 查询 100000~1000100 区间段的数据,仅耗时:18 ms

  • 查询 500000~5000100 区间段的数据,仅耗时:18 ms

  • 查询 1000000~1000100 区间段的数据,仅耗时:18 ms

可以很清晰的看到,带上主键 ID 作为过滤条件,查询性能非常的稳定,基本上在20 ms内可以返回。

这种方案还是非常可行的,如果当前业务对排序要求不多,可以采用这种方案,性能也非常杠

但是如果当前业务对排序有要求,比如通过客户最后修改时间、客户最后下单时间、客户最后下单金额等字段来排序,那么上面介绍的【方案一】,比【方案二】查询效率更高

2.3、方案三:采用 elasticSearch 作为搜索引擎

当数据量越来越大的时候,尤其是出现分库分表的数据库,以上通过主键 ID 进行过滤查询,效果可能会不尽人意,例如订单数据的查询,这个时候比较好的解决办法就是将订单数据存储到 elasticSearch 中,通过 elasticSearch 实现快速分页和搜索,效果提升也是非常明显。

关于 elasticSearch 的玩法,以后有机会再给大家介绍。

三、小结

不知道大家有没有发现,上文中介绍的表主键 ID 都是数值类型的,之所以采用数字类型作为主键,是因为数字类型的字段能很好的进行排序

但如果当前表的主键 ID 是字符串类型,比如 uuid 这种,就没办法实现这种排序特性,而且搜索性能也非常差,因此不建议大家采用 uuid 作为主键ID,具体的数值类型主键 ID 的生成方案有很多种,比如自增、雪花算法等等,都能很好的满足我们的需求。

MySQL大表分页查询优化技巧相关推荐

  1. mysql大表联合查询优化,大事务优化,规避事务超时,锁等待超时与锁表

    背景:最近在做项目的同时做了一些优化,主要针对mysql大表(2亿+数据量未分库分表情况下)的联合查询以及生产上出现的一些事务超时和锁等待超时现象的优化,分享一些我个人的优化思路,只讲思路不贴代码哈. ...

  2. 遍历mysql大表的小技巧

    假如有一个1亿数据的大表(表名是product_info):我们目标是按照某个条件遍历一次比如可能满足条件的数据有10w行,那么每次遍历的时候: 修改前sql: select distinct goo ...

  3. phpstudy mysql建表_MySQL_总结MySQL建表、查询优化的一些实用小技巧,MySQL建表阶段是非常重要的一 - phpStudy...

    总结MySQL建表.查询优化的一些实用小技巧 MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些 ...

  4. 30个mysql千万级大数据SQL查询优化技巧详解

    点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 文章来自:脚本之家 http://www.jb51.net/article/136701 ...

  5. 史上最全MySQL 大表优化方案(长文)

    转载自  史上最全MySQL 大表优化方案(长文) 当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 一.单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑 ...

  6. MySQL 大表优化方案(1)

    转载自  干货!!!MySQL 大表优化方案(1) 当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分 ...

  7. Mysql大数据量查询优化的思路

    项目场景: Mysql大表查询优化,理论上千万级别以下的数据量Mysql单表查询性能处理都是可以的. 问题描述: 在我们线上环境中,出现了mysql几千万级别的日志查询.几百万级别的黑名单库查询分页查 ...

  8. 解决MYSQL大表问题-实战篇(二)

    #首先上表结构 CREATE TABLE `sys_history` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`did` bigint(20) NOT NUL ...

  9. delete mysql 大表_无语了,直到今天,我才揪出MySQL磁盘消耗迅猛的“真凶”!

    作者:dbapower 链接:https://blog.51cto.com/suifu/2135599 背景 Part1:写在最前 当一张单表10亿数据量的表放在你面前,你将面临着什么? Part2: ...

最新文章

  1. python04-列表与元祖
  2. Python:操作文件
  3. 单单表单独占一行_数据透视表→Alt+D+P?
  4. 安装tensorflow_gpu,无法定位程序输入点
  5. mysql 远程攻击_gopher 协议攻击内网 mysql
  6. php image处理,PHP图像处理之imagecreate、imagedestroy函数介绍
  7. UML模型中的图-行为图【交互图-序列图、协作图】
  8. java jtextarea 滚动条_java 在JTextArea中显示 滚动条
  9. 【POJ - 2096】Collecting Bugs(概率dp)
  10. OpenJudge NOI 1.8 17:最好的草
  11. Bengio:我留在学术圈为全人类作贡献,而不是为某一个公司赚钱
  12. Node开发项目管理工具 Grunt 对比 Gulp
  13. 部署桌面虚拟化时要考虑的因素
  14. Numpy中高维axis的操作个人理解
  15. Go - cgo访问C数组 内存
  16. Learning Instagram 学习Instagram Lynda课程中文字幕
  17. php清除页面别人挂的马
  18. excel删除奇数行或者偶数行
  19. 遇到了一个date控件显示的问题
  20. 基于51单片机的校园教室打铃系统

热门文章

  1. 戴尔笔记本(外星人)win10下安装ubuntu18.04双系统历险记
  2. 九省联考2018 林克卡特树
  3. img标签—三种图片格式使用
  4. 服装行业管理软件的降本增效——RFID
  5. 如何把npf号码本从三星手机导入android,将联系人导入三星Galaxy的3种方法
  6. Android大疆无人机对接大牛直播sdk视频H.264码推流
  7. 耗子叔-我的互联网引路人
  8. question2answer之旅
  9. CentOS设置上网代理
  10. 集成学习中的软投票和硬投票机制详解和代码实现