Mysql 查询性能调优总结

一、查询分析性能的相关配置

1.1 配置显示查询性能的参数

在 MySQL 中,SHOW PROFILES 命令用于显示最近的查询性能概况,帮助你分析哪些查询比较耗时。

show profiles;

  • 需要启用参数 profiling,才能使用上述功能,其相关参数设置如下:
// 所有与显示查询性能有关的参数
SHOW VARIABLES LIKE '%profiling%';// 开启显示查询性能的功能
SET profiling = 1;// 是否支持 profiling
SHOW VARIABLES LIKE 'have_profiling';// profiling 历史记录的最大条数
SHOW VARIABLES LIKE 'profiling_history_size';

1.2、Explain 分析

explain 命令可获取 MySQL 如何执行 SELECT 语句的信息,包括是否使用了索引、进行了哪些类型的连接、扫描了多少行数据等。

  • 使用方法

在 select 语句前加上 explain 即可

  • 输出字段解释
字段名说明
select_type查询的类型:比如 SIMPLE(简单的 SELECT,不使用 UNION 或子查询)、PRIMARY(查询中最外层的 SELECT)、UNION(UNION 中的第二个或后续的 SELECT 语句)、DEPENDENT UNION(UNION 中的第二个或后续的 SELECT 语句,取决于外部查询)、SUBQUERY(子查询中的第一个 SELECT)、DEPENDENT SUBQUERY(子查询中的第一个 SELECT,取决于外部查询)等
table输出行所对应的表
type连接类型:ALL(全表扫描)、index(索引全扫描)、range(索引范围扫描)、ref(非唯一性索引扫描,返回匹配某个单值的所有行)、eq_ref(唯一性索引扫描,对于每个索引键,表中最多只有一条匹配行)、const/system(表最多有一个匹配行,通常用于主键或唯一索引比较)、NULL(不用访问表或索引,就能得到所需数据)
possible_keys可能应用在这张表上的索引
key实际使用的索引
ref显示索引的哪一列或常数被用于查找值
rows MySQL 认为必须检查的行数,以找到查询所需行,这是估算的行数

filtered

表示返回结果的行占开始查找行的百分比
extra包含不适合在其他列中显示的额外信息,比如是否使用了文件排序(Using filesort)、是否使用了临时表(Using temporary)、是否使用了回表(Using where)等

mysql官网中有关查询计划的说明:MySQL :: MySQL 8.4 Reference Manual :: 10.8.2 EXPLAIN Output Format

二、性能调优方案

2.1 表及数据量背景介绍

以表 order_master_test 为例,其中含有id主键索引及index_reportDate、index_createAt 辅助索引,数据量为470多万,具体表结构为:

// 创建表
CREATE TABLE `order_masters_test` (`id` bigint NOT NULL AUTO_INCREMENT,`group_id` bigint DEFAULT NULL,`shop_id` bigint DEFAULT NULL,`shop_name` longtext,`report_date` bigint DEFAULT NULL,`order_key` longtext,`order_type` longtext,`total_amount` float DEFAULT NULL,`area_name` longtext,`table_name` longtext,`channel_key` longtext,`channel_name` longtext,`order_status` int unsigned DEFAULT NULL,`create_by` longtext,`create_at` bigint DEFAULT NULL,`paid_amount` float DEFAULT NULL,`promotion_amount` float DEFAULT NULL,`checkout_by` longtext,`checkout_at` bigint DEFAULT NULL,`pay_desc` longtext,`customer_qty` int unsigned DEFAULT NULL,`order_remark` longtext,PRIMARY KEY (`id`),KEY `index_reportDate` (`report_date`),KEY `index_createAt` (`create_at`)
) ENGINE=InnoDB AUTO_INCREMENT=5111719 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;// 插入具体数据及批量插入数据
INSERT INTO order_masters_test
(`group_id`,
`shop_id`,
`shop_name`,
`report_date`,
`order_key`,
`order_type`,
`total_amount`,
`area_name`,
`table_name`,
`channel_key`,
`channel_name`,
`order_status`,
`create_by`,
`create_at`,
`paid_amount`,
`promotion_amount`,
`checkout_by`,
`checkout_at`,
`pay_desc`,
`customer_qty`,
`order_remark`)
VALUES
('955', '12345', '望京总店', '20240620', 'DD20240620111', '堂食', '90', '', '', '', '', '1', '001', '0', '0', '0', '', '0', '', '0', '测试订单11111');insert into order_masters_test(`group_id`,`shop_id`,`shop_name`,`report_date`,`order_key`,`order_type`,`total_amount`,`area_name`,`table_name`,`channel_key`,`channel_name`,`order_status`,`create_by`,`create_at`,`paid_amount`,`promotion_amount`,`checkout_by`,`checkout_at`,`pay_desc`,`customer_qty`,`order_remark`
) 
select `group_id`,`shop_id`,`shop_name`,`report_date`,concat(date_format(now(), '%Y%m%d%H%i%s'), LPAD(FLOOR(1 + (RAND() * 10000)), 4, '0')),`order_type`,`total_amount`,`area_name`,`table_name`,`channel_key`,`channel_name`,`order_status`,`create_by`,date_format(now(), '%Y%m%d%H%i%s'),`paid_amount`,`promotion_amount`,`checkout_by`,`checkout_at`,`pay_desc`,`customer_qty`,`order_remark`
from order_masters_test;

 

需要优化的查询语句为:

select * from order_masters_test where report_date = 20240620 order by create_at desc limit 200000, 10;

当前执行该语句,查询超时,如图:

2.2 初级调优:强制使用更合适的索引

经查询,表中report_date=20240620的数据总共有 524288,且查询执行计划发现,mysql使用了索引 index_reportDate 和文件排序。

  •  分析原因:

mysql 使用 index_reportDate 索引,会首先查出满足条件(report_date=20240620)的52万条索引数据,再根据主键ID回表查找create_at字段,然后对52万条数据的create_at 进行降序排列,最后筛选出第200001到200010条最终数据。

注:此处省略了B+树索引的数据结构介绍,有关内容可以查看Mysql 存储引擎原理探究-CSDN博客

  • 调优方案:

强制使用索引 index_createAt,先查找排好序的create_at值,再回表筛选 reportDate = 20240620 的数据,省去了文件排序的时间

  • 使用方法:

在表名后增加语句 force index(index_createAt)

  • 优化结果:

由查询超时提升到12.7 秒

2.3 中级调优:使用联合索引

  • 分析原因:

经分析,查询语句使用了 report_date 字段过滤条件以及 create_at 字段排序,如果将这两个字段创建联合索引,则查询时间主要分布在查找联合索引及根据主键ID到主键索引中查找完整数据上,不用再进行文件排序等。

  • 调优方案:

创建联合索引,具体sql语句如下:

-- 新建 report_date 和 create_at 字段的联合索引
create index index_reportDate_createAt on order_masters_test(report_date, create_at);

  • 优化结果:

查询时间由12.7秒提升为6.29秒

2.4 高级调优:使用覆盖索引+join关联

  • 分析原因:

查询语句中的 limit 200000,10 表示需要跳过前20万条记录,取接下来的10条数据,在上述两种调优方案中,都需要回表20万+次,其实前20万次回表都是无效的,所以如果能跳过这20万次回表,则能提高很大的查询效率。

  • 调优方案:

通过联合索引 index_reportDate_createAt 先取出符合条件的10条数据的主键ID,当做临时表,再用这10个主键ID关联原表,从而获取完整数据,整个过程只需要回表10次,大大地提升查询性能。具体SQL语句如下:

select b.* from (
select id from order_masters_test 
where report_date = 20240620 order by create_at desc limit 200000, 10) temp
left join order_masters_test b on temp.id = b.id;

  • 优化结果:

 查询时间由6.29秒提升到69毫秒,性能大大提升。

2.5 索引合并

or 条件会使用索引合并,如下图:

不走索引的情况下,可以把 or 条件改为 union(去重)/ union all(不去重) ,如下:

实测中发现,分别执行上述的 where report_date = 20240623 和 create_at=20241219133733 耗时短,但用 union 合起来时则耗时了27s

注意:索引合并仅适用于单表查询

2.6 索引下推

索引下推(Index Condition Pushdown)的执行过程:mysql 数据库会在取出索引的同时,判断是否可以进行 where 条件的过滤,这样就不用先回表再进行where条件过滤发现数据不可用,减少了IO操作。ICP 优化支持 range、ref、eq_ref、ref_or_null 类型的查询,可在执行计划的列 Extra 看到 Using index condition。

2.7 索引失效

总结起来,就是两种场景:没有办法使用索引;使用索引还不如不使用索引

以下情况会导致索引失效:

  • 数据量很小
  • 索引区分度太低:比如性别字段(男、女、未知三个值)建立索引
  • 模糊查询:如 like '%23',不满足最左前缀原则
  • 函数计算
  • 类型隐式转换:字段是字符串型,给定的值是数字,如varchar类型的 address = 1234
  • 占比过大:范围查询数据量超过全表30%,但这不是一个固定比例,还有表大小、行数、IO块大小等影响因素

三、总结

优化概览:

mysql 查询优化的本质是减少IO次数。

3.1 业务层级优化

根据业务场景判断有些查询是否每次都必须。比如查询订单信息时,是否必须查询对应商品明细?如果在订单主表中有字段标识出该订单没有商品明细,则不用再去查询商品明细表。

3.2 数据库层级优化

3.2.1 数据库表设计合理,主键最好使用 int 或 bigint。

不使用uuid等字符串的原因:

①插入顺序问题,可能导致页分裂

②存储占用空间大,而且会导致辅助索引占用的空间也大(辅助索引会保存主键ID)

3.2.2 索引是否合理:是否使用了联合索引、索引覆盖等

3.2.3 表字段类型是否合理

3.2.4 查询的字段是否必须

3.2.5 对于频繁查询的表,可以考虑进行分库分表

3.2.6 使用缓存技术:对于一些相对稳定的查询结果,可以考虑使用缓存技术,如redis等,减少对数据库的访问

3.3 硬件层级优化

CPU、内存、磁盘等

参考视频:MySQL 的一条语句是如何执行的?_哔哩哔哩_bilibili

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python中使用selenium执行组合快捷键ctrl+v不生效问题

在执行ctrlv进行粘贴时,绑定一个页面上的元素对象(无论元素对象是否是引用过期或者是粘贴的目标文本区,但前提需要粘贴的目标文本区获取焦点)执行ctrlv后可以生效。执行粘贴组合快捷键(ctrlv)的示例代码 se…

C++模板:编译时模拟Duck Typing

C泛型与多态(4): Duck Typing - 简书 James Whitcomb Riley在描述这种is-a的哲学时,使用了所谓的鸭子测试(Duck Test): 当我看到一只鸟走路像鸭子,游泳像鸭子,叫声像鸭子,那我就把它…

【求职面试】驾照的种类

大型客车 A1 大型载客汽车 A3、B1、B2、C1、C2、C3、C4、M 牵引车 A2 重型、中型全挂、半挂汽车列车 B1、B2、C1、C2、C3、C4、M 城市公交车 A3 核载10人以上的城市公共汽车 C1、C2、C3、C4 中型客车 B1 中型载客汽车(10人以上、19人以下) C1、C2、C3…

PyQt实战——使用python提取JSON数据(十)

系类往期文章: PyQt5实战——多脚本集合包,前言与环境配置(一) PyQt5实战——多脚本集合包,UI以及工程布局(二) PyQt5实战——多脚本集合包,程序入口QMainWindow(三&…

RAG实战:构建基于本地大模型的智能问答系统

RAG实战:构建基于本地大模型的智能问答系统 引言 在当今AI快速发展的时代,如何构建一个既智能又可靠的问答系统是一个重要课题。本文将介绍如何使用RAG(检索增强生成)技术,结合本地大模型,构建一个高效的智…

OAuth 2.0

简介 OAuth 是一种开放标准的授权协议或框架,它提供了一种安全的方式,使第三方应用程序能够访问用户在其他服务上的受保护资源,而无需共享用户的凭证(如用户名和密码)。OAuth 的核心思想是通过“授权令牌”来代替直接…

IntelliJ IDEA 远程调试

IntelliJ IDEA 远程调试 在平时开发 JAVA 程序时,在遇到比较棘手的 Bug 或者是线上线下结果不一致的情况下,我们会通过打 Log 或者 Debug 的方式去定位并解决问题,两种方式各有利弊,今天就简要介绍下如何通过远程 Debug 的情况下…

美国辅料查询之FDA批准药用辅料数据库(IID数据库)

药用辅料的性质很大程度上决定了制剂的性质,每一种新的药用辅料的问世,都会为制剂技术的发展带来新的机遇,每一种药用辅料都可能让制剂研发员开发出新剂型药物,所以在药物制剂研发过程中,药用辅料的信息调研是不可或缺…

YOLOv10目标检测-训练自己的数据

yolov10 https://github.com/THU-MIG/yolov10?tabreadme-ov-file 1. 数据集 模型的建立需要收集图片并且进行标注。YOLOv10标注的文件格式如下(每张图片对应一个标签文件): 0 0.441753 0.815461 0.061021 0.042763 1 0.395895 0.759868 …

Redis学习(五)优惠券秒杀2——分布式锁

Redis学习(五)优惠券秒杀2 一、分布式锁-redission二、快速入门三、redission可重入锁原理四、redission锁的MutiLock原理 一、分布式锁-redission 基于setnx实现的分布式锁存在下面的问题: 重入问题:重入问题是指 获得锁的线程…

Flink调优----资源配置调优与状态及Checkpoint调优

目录 第 1 章 资源配置调优 1.1 内存设置 1.1.1 TaskManager 内存模型 1、内存模型详解 2、案例分析 1.1.2 生产资源配置示例 1.2 合理利用 cpu 资源 1.2.1 使用 DefaultResourceCalculator 策略 1.2.2 使用 DominantResourceCalculator 策略 1.2.3 使用 DominantRes…

Docker怎么关闭容器开机自启,批量好几个容器一起操作?

环境: WSL2 docker v25 问题描述: Docker怎么关闭容器开机自启,批量好几个容器一起操作? 解决方案: 在 Docker 中,您可以使用多种方法来关闭容器并配置它们是否在系统启动时自动启动。以下是具体步骤和…

模型的量化(Quantization)

文章目录 一、浮点数格式:FP64, FP32, FP16, BFLOAT16, TF32之间的相互区别1、关于浮点数2、常见的浮点数格式 二、量化(Quantization)1、基本概念2、量化的实现8bit量化4bit量化 三、QLora四、大语言模型量化方法对比:GPTQ、GGUF…

勤云远程稿件处理系统 SQL注入漏洞复现(XVE-2024-18393)

0x01 产品简介 勤云远程稿件处理系统(又称勤云采编系统)是北京勤云科技发展有限公司研发的一款产品,是一款全网络版期刊采编管理系统,旨在解决从投稿到稿件发表整个过程的信息化管理问题。该系统集成了搜索引擎、云计算等先进技术,为编辑部、作者和审稿人提供了便捷、高效…

谷歌Gemini与Anthropic Claude对比测试引发争议:AI竞赛暗流涌动

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

vLLM (2) - 架构总览

系列文章目录 vLLM (1) - Qwen2推理&部署 vLLM (2) - 架构总览 vLLM (3) - Sequence & SequenceGroup vLLM (4) - LLMEngine上篇 vLLM (5) - LLMEngine下篇 vLLM (6) - Scheduler & BlockSpaceManager 文章目录 系列文章目录前言一、官方资料二、原理简述三、架构…

QT从入门到精通(三)——实现文件列表遍历的图像浏览器

使用 Qt 实现文件列表遍历的图像浏览器 在本篇博客中将介绍如何使用 Qt 框架创建一个简单的图像浏览器应用程序。该应用程序能够选择文件夹,遍历其中的图像文件,并显示这些图像。我们将重点关注如何使用 Qt 的文件对话框和 OpenCV 库来处理图像。 1. 项…

强化特种作业管理,筑牢安全生产防线

在各类生产经营活动中,特种作业由于其操作的特殊性和高风险性,一直是安全生产管理的重点领域。有效的特种作业管理体系涵盖多个关键方面,从作业人员的资质把控到安全设施的配备维护,再到特种设备的精细管理以及作业流程的严格规范…

数据库管理-第274期 Oracle Enterprise Manager 24ai新特性一览(20241223)

数据库管理274期 2024-12-23 数据库管理-第274期 Oracle Enterprise Manager 24ai新特性一览(20241223)1 增强的企业管理联邦2 新的导航菜单3 EM仪表盘增强4 使用远程代理进行监控5 0停机监控6 新的作业系统控制台7 Oracle Key Vault支持8 自治数据库的引…

将Minio设置为Django的默认Storage(django-storages)

这里写自定义目录标题 前置说明静态文件收集静态文件 使用django-storages来使Django集成Minio安装依赖settings.py测试收集静态文件测试媒体文件 前置说明 静态文件 Django默认的Storage是本地,项目中的CSS、图片、JS都是静态文件。一般会将静态文件放到一个单独…