当前位置: 首页 > news >正文

Mysql大数据量分页优化

前言

之前有看过到mysql大数据量分页情况下性能会很差,但是没有探究过它的原因,今天讲一讲mysql大数据量下偏移量很大,性能很差的问题,并附上解决方式。

原因

将原因前我们先做一个试验,我做试验使用的是mysql5.7.24版本(mysql8上我也试验出来同样的问题),看看mysql是不是在偏移量比较大的时候分页会比较慢,性能比较差

版本

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.24    |
+-----------+
1 row in set (0.00 sec)

表结构

CREATE TABLE `trace_monitor_log` (`id` varchar(30) NOT NULL COMMENT '表主键id',`user_id` varchar(30) DEFAULT NULL COMMENT '用户id',`trace_id` varchar(30) DEFAULT NULL COMMENT '追踪id',`trace_type` varchar(30) DEFAULT NULL COMMENT '追踪类型',`path` mediumtext COMMENT '追踪路径',`source_ip` varchar(255) DEFAULT NULL COMMENT '来源ip',`ext_params` mediumtext COMMENT '请求扩展参数',`costs` int(11) DEFAULT '0' COMMENT '请求耗时(毫秒)',`exception` mediumtext COMMENT '异常信息',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`),KEY `trace_id` (`trace_id`),KEY `trace_type` (`trace_type`),KEY `create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='监控日志表';

试验过程

这个是我从测试环境找的一张日志表,里面的数据量是580万左右,我们先看看只查询普通10条数据的情况。

数据量

mysql> select count(*) from trace_monitor_log;
+----------+
| count(*) |
+----------+
|  5806836 |
+----------+
1 row in set (1.66 sec)
explain select * from trace_monitor_log order by trace_id limit 10;

image-20240128210052009

可以看到没有offset偏移量的时候可以直接走索引,key是trace_id,并且只查询了10条数据。

我们在来看看如果offset是1000的时候。

explain select * from trace_monitor_log order by trace_id limit 10 offset 1000;

image-20240128210345205

可以看到偏移量比较小的时候还是可以走索引,rows是1010,这时候发现虽然我们只要查询10条数据,但是查询的时候还是会扫描1000条无用的索引记录。

我们接下往下把offset加到100万

explain select * from trace_monitor_log order by trace_id limit 10 offset 1000000;

image-20240128210656849

这个时候就会发现一个神奇的现象,竟然没有走索引了,type是ALL,就是全表扫描了,执行时间大概花了40多秒,性能确实很差。这里的原因,本来根据索引查出来100万条记录,然后把不需要的数据给丢弃掉,mysql会计算查询成本,发现这样走索引还没有全表扫描快,所以用了全表扫描,但是全表扫描就为了拿到十条数据显然是性能很差的。mysql并不会自动判断先根据trace_id的索引找到偏移量需要的10条数据,再根据这10条索引找到叶子节点的主键记录去回表查询数据,导致了这么差的性能。

解决方式

1.延迟关联

先使用覆盖索引的方式找到对应order by 之后的limit条索引,因为是覆盖索引,直接用的索引记录,没有回表所以很快。接着在使用join的方式,将索引记录和原表关联起来就可以查出来对应的limit条数据。

explain select * from trace_monitor_log t1 join (select trace_id from trace_monitor_log  order by trace_id limit 1000000,10) t2 on t1.trace_id = t2.trace_id

image-20240128211946406

image-20240128212044859

执行时间平均在500-600毫秒左右,相比全表扫描快了很多。

2.书签记录

这个概念我也是从网上看到的,还没找到具体这个概念的出处在哪里。不过不要困于这个概念,只要理解是先找到对应要查询一条索引记录(书签),再根据这个索引去范围查询对应的limit条数数据就容易理解了。

explain select * from trace_monitor_log t1 where trace_id > (select trace_id from trace_monitor_log  order by trace_id limit 999999,1)   order by trace_id limit 10

image-20240128212614389

image-20240128213228356

执行时间和延迟关联差不多,也都走了索引,所以性能也比较好。

参考资料

1.mysql8官网limit优化

2.要想通过面试,MySQL的Limit子句底层原理你不可不知

3.从官方文档中探索MySQL分页的几种方式及分页优化

http://www.lryc.cn/news/289898.html

相关文章:

  • QT tcp与udp网络通信以及定时器的使用 (7)
  • web架构师编辑器内容-添加自动保存的功能
  • 【Redis】关于它为什么快?使用场景?以及使用方式?为何引入多线程?
  • SpringBoot之JWT登录
  • 【备战蓝桥杯】——循环结构
  • 【数据分享】1929-2023年全球站点的逐年平均气温数据(Shp\Excel\免费获取)
  • 探索Pyecharts关系图绘制技巧:炫酷效果与创意呈现【第42篇—python:Pyecharts水球图】
  • 蓝桥杯-循环节长度
  • Jython调用openwire库连接activemq转发topic订阅消息到另一个activemq 服务器上 完整代码
  • 面试经典题---30.串联所有单词的子串
  • 字符串随机生成工具(开源)-Kimen(奇门)
  • UE4 CustomDepthMobile流程小记
  • Docker 基础篇
  • Idea上操作Git回退本地版本,怎么样保留已修改的文件,回退本地版本的四种方式代表什么?
  • vue3封装el-pagination分页组件
  • 负载均衡下Webshell连接思路及难点
  • 基于链表实现贪吃蛇游戏
  • Python网络爬虫实战——实验6:Python实现js逆向与加解密
  • 【python】使用aiohttp库编写一个简单的异步服务器
  • 新手使用代理IP接入代码教程
  • JVM问题排查手册
  • 前端canvas项目实战——简历制作网站(三)——右侧属性栏(线条宽度样式)
  • 字节跳动二面经典题目
  • 微搭低代码从入门到精通01应用介绍
  • 论文阅读《thanking frequency fordeepfake detection》
  • ArcgisForJs快速入门
  • 【解决方法】git pull报错ssh: connect to host github.com port 22: Connection timed out
  • 30天精通Nodejs--第三十天:项目实战-物联网应用
  • java 社区资源管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
  • 网络编程套接字(Socket)