千万级别的表分页查询非常慢,怎么办?

一、问题复现

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

以订单表为例,假如每天的订单量在 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 的生成方案有很多种,比如自增、雪花算法等等,都能很好的满足我们的需求。

本文主要围绕大表分页查询性能问题,以及对应的解决方案做了简单的介绍,如果有异议的地方,欢迎网友留言,一起讨论学习!

如果想获取更多的大数据库相关的资料,可以关注下方二维码,后台回复 【 cccc】有我准备的一线程序必备计算机书籍、大厂面试资料和免费电子书,希望可以帮助大家提升技术和能力。

Original: https://www.cnblogs.com/dxflqm/p/16544552.html
Author: 程序员志哥
Title: 千万级别的表分页查询非常慢,怎么办?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/612822/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • CentOs安装Nginx

    安装 gcc pcre pcre-devel zlib OpenSSL 安装 安装 nginx 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,则需…

    数据库 2023年6月11日
    085
  • 数据库设计的十个最佳实践

    数据库是应用及计算机的核心元素,负责存储运行软件应用所需的一切重要数据。为了保障应用正常运行,总有一个甚至多个数据库在默默运作。我们可以把数据库视为信息仓库,以结构化的方式存储了大…

    数据库 2023年5月24日
    0101
  • Java数据结构和算法

    一、数据结构 数据结构是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。 通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同…

    数据库 2023年6月11日
    099
  • Linux 下安装 redis

    2、使用命令下载: 3、将文件拷贝到安装目录 /usr/local 目录下 4、进入 /usr/local 目录下,解压安装包 5、进入解压后的目录 6、编译,将 redis 安装…

    数据库 2023年6月14日
    091
  • 1_Layui

    官网:https://www.layui.com/ 在官网首页, 可以很方便的下载Layui Layui是一款经典模块化前端UI框架, 我们只需要定义简单的HTML,CSS,JS即…

    数据库 2023年6月11日
    092
  • Docker Maven构建缓存spring boot依赖包

    背景 每次通过 docker build ‘xxx’ 的时候,总是会去maven镜像下载一大堆Jar包,平均每次build都要在3分钟左右,效率非常低下,于…

    数据库 2023年6月6日
    095
  • 生成随机数的若干种方法

    背景: 创建账户时我们需要配置初始随机密码,使用手机号注册时需要随机验证码,抽奖活动需要随机点名,俄罗斯方块游戏需要随机出形状。这些案例都在说明一个问题,随机数据很重要!而在 Sh…

    数据库 2023年6月14日
    065
  • 数据连接池

    dbcp 1.引入jar包 导入这两个jar包 下载jar包地址:Maven Repository: Search/Browse/Explore (mvnrepository.co…

    数据库 2023年5月24日
    092
  • Mysql的读写分离中间件该怎么写?听我来说。

    网上有很多读写分离的中间件,像proxy,mycat等等,由于本人比较懒,懒得去读各种开源的东西,还是想造轮子来得快。 1、了解mysql通信协议,其中有分4.1之前和4.1版本的…

    数据库 2023年5月24日
    0119
  • day42-反射01

    Java反射01 1.反射(reflection)机制 1.1反射机制问题 一个需求引出反射 请看下面问题: 根据配置文件 re.properties 指定信息,创建Cat对象并调…

    数据库 2023年6月11日
    0126
  • MyBatis(二)-CURD (ResultMap 一对一,一对多)

    1、insert 标签 1.1 获取SqlSessionFactory 对象的通用方法 方便后面分测试; //获取SqlSessionFactory 对象的通用方法 public …

    数据库 2023年6月16日
    076
  • SpringCloudAlibaba 实战

    SpringCloudAlibaba 实战 服务发现Nacos 服务发现原理 负载均衡Ribbon 细粒度修改Ribbon负载均衡规则 指定Ribbon全局负载均衡规则 配置Rib…

    数据库 2023年6月6日
    0109
  • Debezium的基本使用(以MySQL为例)

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 一、Debezium介绍 摘自官…

    数据库 2023年5月24日
    0101
  • day02-MySQL基础知识

    MySQL基本知识 1.数据库 1.1.创建数据库 语法: CREATE DATABASE [IF NOT EXISTS] db_name [create_specificatio…

    数据库 2023年6月11日
    092
  • java.sql.SQLException: The server time zone value is unrecognized

    在写Mysql数据库连接工具的时候出现了这样的报错,其实原因写的挺清楚的 就是在连接的时候没有加上时区的信息; 解决办法就是在JDBC连接的URL里面加上serverTimezon…

    数据库 2023年6月6日
    083
  • RadonDB MySQL on K8s 2.1.4 发布

    RadonDB MySQL Kubernetes 于 4 月 7 日正式发布新版本 2.1.4。该版本主要对可用性进行了优化,新增中英文文档,并修复一些问题。 致谢 首先感谢 @a…

    数据库 2023年6月11日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球