【性能优化】MySQL百万数据深度分页优化思路分析

news2025/5/24 10:40:30

业务场景

        一般在项目开发中会有很多的统计数据需要进行上报分析,一般在分析过后会在后台展示出来给运营和产品进行分页查看最常见的一种就是根据日期进行筛选。这种统计数据随着时间的推移数据量会慢慢的变大,达到百万、千万条数据只是时间问题。

一、数据准备(生成百万数据)

sql:将your_table_name 改成自己的表名,目前我的表中有id,name,password、create_time四个字段(这个是生成一百万数据的,会有点影响性能,插入比较耗时)

INSERT INTO `your_table_name ` (name, password, create_time, age)
SELECT 
    SUBSTRING(MD5(RAND()), 1, 10),
    SUBSTRING(MD5(RAND()), 1, 10),
    NOW() - INTERVAL FLOOR(RAND() * 31536000) SECOND,
    FLOOR(RAND() * 100) + 1
FROM
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t1,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t2,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t3,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t4,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t5,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t6,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t7,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t8,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t9,
    (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) t10;

可以选择每次插入10万条数据,多次插入效果比一次插入效果更好。

建表SQL:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) DEFAULT NULL COMMENT '名字',
  `password` varchar(50) DEFAULT NULL COMMENT '密码',
  `age` int(3) DEFAULT NULL COMMENT '年龄',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

二、场景复现

创建了一张user表,给create_time字段添加了索引。并在该表中添加了100w条数据。

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) DEFAULT NULL COMMENT '名字',
  `password` varchar(50) DEFAULT NULL COMMENT '密码',
  `age` int(3) DEFAULT NULL COMMENT '年龄',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

查询前10条基本上不消耗什么时间

SELECT SQL_NO_CACHE * 
FROM `user`
WHERE create_time BETWEEN '2023-01-01' AND '2023-05-23'
LIMIT 1,10;

从第100w+开始取数据的时候,查询耗时1.5秒。

SELECT SQL_NO_CACHE * 
FROM `user`
WHERE create_time BETWEEN '2023-01-01' AND '2023-05-23'
LIMIT 1000000,10;

SQL_NO_CACHE
这个关键词是为了不让SQL查询走缓存。

同样的SQL语句,不同的分页条件,两者的性能差距如此之大,那么随着数据量的增长,往后页的查询所耗时间按理会越来越大。

三、问题分析

1、回表

我们一般对于查询频率比较高的字段会建立索引。索引会提高我们的查询效率。我们上面的语句使用了SELECT * FROM user,但是我们并不是所有的字段都建立了索引。当从索引文件中查询到符合条件的数据后,还需要从数据文件中查询到没有建立索引的字段。那么这个过程称之为回表

2、覆盖索引

如果查询的字段正好创建了索引了,比如 SELECT create_time FROM user,我们查询的字段是我们创建的索引,那么这个时候就不需要再去数据文件里面查询,也就不需要回表。这种情况我们称之为覆盖索引

3、IO

回表操作通常是IO操作,因为需要根据索引查找到数据行后,再根据数据行的主键或唯一索引去聚簇索引中查找具体的数据行。聚簇索引一般是存储在磁盘上的数据文件,因此在执行回表操作时需要从磁盘读取数据,而磁盘IO是相对较慢的操作。

4、问题衍生

当我们查询 LIMIT 2000,10 会不会扫描1-2000行,你之前有没有跟我一样,觉得数据是直接从2000行开始取的,前面的根本没扫描或者不回表。其实这样的写法,一个完整的流程是查询数据,如果不能覆盖索引,那么也是要回表查询数据的。

所以越到后面大概率是会查询越慢!

四、问题总结

我们现在知道了LIMIT 遇到后面查询的性能越差,性能差的原因是因为要回表,既然已经找到了问题那么我们只需要减少回表的次数就可以提升查询性能了。

五、解决方案

既然覆盖索引可以防止数据回表,那么我们可以先查出来主键id(主键索引),然后将查出来的数据作为临时表然后 JOIN 原表就可以了,这样只需要对查询出来的5条结果进行数据回表,大幅减少了IO操作。

六、优化前后性能对比

我们看下执行效果:

  • 优化前:1.5s 

SELECT SQL_NO_CACHE * 
FROM `user`
WHERE create_time BETWEEN '2003-01-01' AND '2003-05-23'
LIMIT 1000000,10;

 

  • 优化后:0.6s 

SELECT SQL_NO_CACHE * 
FROM `user`
WHERE create_time BETWEEN '2003-01-01' AND '2023-05-23'
LIMIT 1000000,10;

SELECT SQL_NO_CACHE *
FROM (SELECT SQL_NO_CACHE id 
FROM `user`
WHERE create_time BETWEEN '2003-01-01' AND '2023-05-23'
LIMIT 1000000,10) AS temp
INNER JOIN `user` AS u ON u.id = temp.id; 

查询耗时性能大幅提升。这样如果分页数据很大的话,也不会像普通的limit查询那样慢。

总结:

        其实实际业务场景数据达到百万了都会选择三方工具了,比如:ES,本文只是拿分页数据做例子,探讨一下SQL的查询效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/785289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于脑电睡眠分期,你应该知道的还有这些

导读 基于电生理信号(EEG,EOG和EMG)对睡眠阶段进行识别的建议源自Rechtschaffen和Kales手册,由美国睡眠医学学会于2007年发布,并定期更新多年。这些建议对于评估不同类型的睡眠/觉醒主观评定中的客观标志物非常重要。凭借研究的简单、可重复…

windows/linux/mac上编译open3d 0.17.0

目录 写在前面准备编译windows:linux/mac:注: 参考完 写在前面 1、本文内容 windows/linux/mac上编译open3d 0.17.0 2、平台 通过cmake构建项目,跨平台通用 3、转载请注明出处: https://blog.csdn.net/qq_41102371/article/details/1318918…

基于C++的QT基础教程学习笔记

文章目录: 来源 教程社区 一:QT下载安装 二:注意事项 1.在哪里写程序 2.如何看手册 3.技巧 三:常用函数 1.窗口 2.相关 3.按钮 4.信号与槽函数 5.常用栏 菜单栏 工具栏 状态栏 6.铆接部件 7.文本编辑 8…

[ELK安装篇]:基于Docker虚拟容器化(主要LogStash)

文章目录 一:前置准备-(参考之前博客):1.1:准备Elasticsearch和Kibana环境:1.1.1:地址:https://blog.csdn.net/Abraxs/article/details/128517777 二:Docker安装LogStash(数据收集引擎&#xff…

SH-FAPI-4,新型tumor显像剂,其中FAPI通过与FAP结合

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ SH-FAPI-4 其中FAPI通过与FAP结合,可在PET-CT扫描中可视化tumor的位置和大小,从而帮助确定tumor的类型和位置,并指导tumor treatment的选择。FAPI被认为是一种具有潜在应用前景的新型tu…

vue检测数据变化的原理

vue监测数据变化的原理 vue会监视data中所有层次的数据。 监测对象类型的数据 原理 vue监测对象类型的数据通过setter实现,且要在new Vue时就传入要监测的数据。 对象中后追加的属性,Vue默认不做响应式处理;如需后续添加的属性做响应式&am…

吉林大学计算机软件考研经验贴

文章目录 简介政治英语数学专业课 简介 本人23考研,一战上岸吉林大学软件工程专硕,政治72分,英一71分,数二144分,专业课967综合146分,总分433分,上图: 如果学弟学妹需要专业课资料…

STM32MP157驱动开发——按键驱动(定时器)

“定时器 ”机制: 内核函数 定时器涉及函数参考内核源码:include\linux\timer.h 给定时器的各个参数赋值: setup_timer(struct timer_list * timer, void (*function)(unsigned long),unsigned long data):设置定时器&#xf…

HALCON error #5504 Image too large for this HALCON version in operator问题解决

目录: 一,问题概述:二,解决方法 一,问题概述: 🌀当你直接或间接使用Halcon来做图像读取的时候,你可能遇到5504错误:HalconDotNet.HOperatorException:HALCON error #5504…

传奇开区网站打开跳转到别的网站处理教程

打开跳转被劫持到其他网站如何处理教程。 在解决劫持之前,需要先确定一下身份,如果是网站被劫持了,或者是访客访问自己的网站被劫持到其他的网站上,解决起来的方法不一样,下面一休分类分享给大家 1、访客身份处理方法…

opencv-19 图像色彩空间转换函数cv2.cvtColor()

cv2.cvtColor() 函数是 OpenCV 中用于图像颜色空间转换的函数。它允许你将图像从一个色彩空间转换为另一个色彩空间。在 Python 中,你可以使用这个函数来实现不同色彩空间之间的转换。 函数的基本语法为: cv2.cvtColor(src, code[, dst[, dstCn]])参数…

提高可视性的五大方法可增强 Horizon Cloud 下一代平台的性能和用户体验

我们在 VMware Explore US 2022 推出了 VMware Horizon Cloud 下一代平台。该平台为使用现代化虚拟桌面和应用的客户提供了一个新的混合型桌面服务(DaaS)架构,其围绕降低成本和提高可扩展性而构建。首次发布后,我们在 VMware Expl…

Java | 数组排序算法

一、冒泡排序 冒泡排序的基本思想是对比相邻的元素值,如果满足条件就交换元素值,把较小的元素移到数组前面,把较大的元素移到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部升到顶…

Python2、python3的安装

目录 一、环境搭建和简单命令 1. 关于交互模式 2.执行文件 3. print 4. 安装/卸载包 5. 查看安装了哪些包 6. 升级pip本身 7. 查看包的具体信息 8. 搜索含有nose 9. 所有包升级到最新版本 二、其他说明 1. –m的使用 2. 切换盘符 资料获取方法 一、环境搭建和简单…

vue3 项目打包后白屏

根据Vue3.x文档,在 vue.config.js/vite.config.ts 统一对webpack、跨域、端口号等属性进行配置。 1.在 vue.config.js/vite.config.ts添加publicPath属性并将值更改成 ‘./’ 在这里插入图片描述 2.若还没有解决就去路由中将history模式设置成默认的Hash模式&…

MATLAB与ROS联合仿真——Simulink生成ROS代码

当我们用simulink完成控制程序的搭建后,我们期望下一次可以直接对ROS进行控制,而不是每次都需要启动matlab和simulink,因此我们可以使用simulink的代码生成器,生成ROS代码 1、生成代码前需要进行如下的设置 (1&#xf…

Fuzz测试:提升自动驾驶安全性

目录 什么是Fuzz测试? 自动驾驶的潜在风险 Fuzz测试:自动驾驶和车联网 Fuzz测试方法有以下几种: 资料获取方法 纵观近百年来汽车制造业的发展历程,产业跨进的每一步背后都有着技术创新作为支撑。汽车技术创新对世界经济、社会…

openCV-python安装

同样在anaconda下创建一个opencv-python环境 首先,打开anaconda navigator,然后创建一个环境来放opencv-python。 先点击下面的create,然后创建一个新环境。 选择你的python版本,这里我选择的是Python3.6。你也可以根据你的需要和习惯来选择…

【前后端数据交互】原生JS的Fetch请求封装

一、 AJAX 和 Fetch 对比 1.1 AJAX 概述 AJAX 是最早出现请求数据的方式,它不需要不需要刷新整个页面即可更新部分数据。 属于原生 JS 范畴 ,技术核心是 XMLHttpRequest 对象。 AJAX 请求过程:创建 XMLHttpRequest 对象、连接服务器、发送请…

持续上新丨美格智能推出高算力AI模组SNM930,支持运行Linux Ubuntu

近日,美格智能宣布推出最新的高算力AI模组SNM930。该模组基于高端SoC高通QCS6490平台研发设计,支持WiFi 6E和蓝牙5.2连接,AI算力高达14Tops,是行业首款除支持Android外,还可以运行 Linux Ubuntu的智能模组,…