MySQL如何定位慢查询以及使用EXPLAIN对SQL进行性能分析

在数据库的日常运维和开发中,SQL慢查询是一个常见且必须高度关注的问题。它不仅会影响用户体验,还可能对系统稳定性构成严重威胁。尤其是在数据量激增的情况下,如从几千到1万的数据增长到百万级,SQL查询的性能问题尤为突出。最近,我们在维护一个项目时,就遇到了这样一个挑战:某个接口的响应时间异常长,经过分析发现,问题出在SQL多表联查上。

SQL慢查询的原因

随着数据量从几千到1万快速增长到百万级,原本设计合理的SQL查询可能变得不再高效。其中,多表联查是一个常见的性能瓶颈。当多个表通过JOIN操作连接时,如果缺少合适的索引或查询条件,就可能导致数据库执行笛卡尔积操作,即返回两个表中所有可能的组合,这会消耗大量的计算资源和时间

定位慢查询

  1. 慢查询日志:大多数数据库系统都提供了慢查询日志功能,可以记录执行时间超过设定阈值的SQL语句。通过分析这些日志,我们可以快速定位到慢查询语句。
  2. 性能监控工具:使用数据库性能监控工具,可以实时监控SQL语句的执行情况,包括执行时间、扫描行数、返回行数等关键指标。这些工具通常还提供了图形化界面,方便我们直观地查看和分析数据。
  3. EXPLAIN命令:对于MySQL等数据库,我们可以使用EXPLAIN命令来查看SQL语句的执行计划,从而了解查询是如何被数据库执行的。通过分析执行计划,我们可以发现是否存在索引缺失、全表扫描等问题。

开启慢查询日志(MySQL为例)

在MySQL中,开启慢查询日志(Slow Query Log)可以识别那些执行时间超过预定阈值的查询。以下是如何在MySQL中开启慢查询日志的步骤和示例配置:

1.登录到MySQL服务器

登录到MySQL服务器。

mysql -u root -p

2.检查当前慢查询日志设置 

在MySQL命令行中,你可以查询@@slow_query_log变量来检查慢查询日志是否已经开启:

SHOW VARIABLES LIKE 'slow_query_log';

以及查询long_query_time变量来查看慢查询的阈值(以秒为单位): 

SHOW VARIABLES LIKE 'long_query_time';

 3.开启慢查询日志

 可以通过修改MySQL配置文件(my.cnfmy.ini,取决于你的操作系统和安装方式)来永久开启慢查询日志,或者在MySQL命令行中动态设置(但重启后失效):

动态设置(重启后失效):

SET GLOBAL slow_query_log = 1;  
SET GLOBAL long_query_time = 2;  -- 设置慢查询阈值为2秒

在配置文件中设置(需要重启MySQL服务):

编辑MySQL配置文件(例如/etc/mysql/my.cnf),添加下面几行:

[mysqld]  
slow_query_log = 1  
slow_query_log_file = /var/log/mysql/mysql-slow.log  -- 指定慢查询日志文件的路径  
long_query_time = 2  -- 设置慢查询阈值为2秒  
log_queries_not_using_indexes = 1  -- 可选,记录没有使用索引的查询

然后记得重启MySQL服务

sudo service mysql restart
查看慢查询日志

例:

# Time: 2024-06-27T01:19:58.175560Z
# User@Host: skip-grants user[root] @ localhost [::1]  Id:     3
# Query_time: 6.879824  Lock_time: 0.042471 Rows_sent: 1224444  Rows_examined: 3948281
use jksy_pingshan;
SET timestamp=1719451198;
SELECT * from visit_question_result vqr  join question q on q.id = vqr.question_id join anwser a on a.id = vqr.anwser_id;

1.时间戳和查询基本信息

每条记录的开头都有时间戳,如# Time: 2024-06-27T01:19:58.175560Z,这表示查询发生的精确时间,对分析查询发生的时间顺序很有帮助。接下来的“User@Host”信息说明了执行查询的用户和来源地址,例如skip-grants user[root] @ localhost [::1],表明是root用户从本地主机发起的查询。(注意这个时间是国际时间,不是北京时间)

2.查询时间统计

  • Query_time: 这个字段显示了查询的总执行时间(单位通常是秒),例如Query_time: 6.879824
  • Lock_time: 表示查询在等待锁上的总时间,如果这个值较高,可能意味着有锁竞争问题。
  • Rows_sent 和 Rows_examined: 分别代表查询返回了多少行数据以及在查找过程中检查了多少行。这两个值可以帮助评估查询效率,如果Rows_examined远大于Rows_sent,可能意味着索引使用不当或查询不够高效。

3. SQL查询内容

紧随其后的是实际执行的SQL语句,例如:

SELECT * from visit_question_result vqr  join question q on q.id = vqr.question_id join anwser a on a.id = vqr.anwser_id;

这部分信息让您直接看到导致日志记录的具体查询。 

4.特殊指令

SET timestamp=...; 这样的行出现在每个查询前,是用来设定查询的时间基准,用于在事务复制或其它需要时间一致性的场景中确保时间的一致性。

5.性能分析

在某些日志条目中,还会看到对INFORMATION_SCHEMA.PROFILING的查询,它提供了查询执行过程中的详细步骤及其耗时,是进行性能调优的重要参考。例如:

SELECT STATE AS `Status`, ROUND(SUM(DURATION),7) AS `Duration`, ... FROM INFORMATION_SCHEMA.PROFILING ...

可以帮助识别查询中的哪个阶段最消耗时间,进而针对性优化。

删除慢查询日志
mysqladmin -uroot -p flush-logs slow

 使用mysqldumpslow工具进行MySQL性能分析

mysqldumpslow是MySQL自带的一个工具,用于解析慢查询日志,并输出按查询时间排序的查询列表。它可以从慢查询日志中提取出查询的摘要信息,并按照查询时间、查询次数或锁定时间等指标进行排序,从而帮助我们快速定位性能瓶颈。

使用mysqldumpslow的基本语法如下:

mysqldumpslow [options] [logfile ...]

其中,logfile是慢查询日志文件的路径。options是可选的参数,用于指定排序方式、输出格式等。

以下是一些常用的选项:

  • -s: 指定排序方式,如按查询时间(t)、锁定时间(l)、查询次数(c)等。
  • -t: 显示前N个查询。
  • -g: 正则表达式匹配,只显示符合指定模式的查询。
  • -v: 详细输出,显示查询的完整内容。

例如,如果你想按照查询时间对慢查询日志进行排序,并只显示前10个查询,可以使用以下命令:

mysqldumpslow -s t -t 10 /path/to/slow-query.log

mysqldumpslow的输出通常包含以下几个部分:

  • 查询时间: 查询执行的总时间。
  • 锁定时间: 查询在MySQL内部锁上表或行的时间。
  • 查询次数: 该查询在慢查询日志中出现的次数。
  • 查询语句: 实际的SQL查询语句。
如何利用mysqldumpslow进行性能调优?
  1. 定位问题查询:首先,使用mysqldumpslow找出最耗时的查询。这些查询通常是性能调优的重点。
  2. 分析查询语句:检查问题查询的SQL语句,看是否有优化的空间。例如,是否可以通过添加索引、修改查询逻辑或调整查询参数等方式来优化查询性能。
  3. 优化数据库结构:如果查询语句本身没有问题,那么可能需要考虑优化数据库结构。例如,可以通过调整表的设计、创建合适的索引或优化表的存储引擎等方式来提升性能。
  4. 调整MySQL配置:在某些情况下,可能需要调整MySQL的配置参数来优化性能。例如,可以增加缓存大小、调整线程池大小或启用某些性能优化选项等。
  5. 监控和持续调优:性能调优是一个持续的过程。在调优完成后,需要定期监控数据库的性能,并根据实际情况进行持续的调优。

使用Explain对SQL语句进行性能分析

MYSQL中有专门负责优化SELECT语句的优化器模块,主要功能:通过分析系统中收集到的统计信息,为客户端请求的Query提供它认为的最优执行计划,这个执行计划展示了接下来具体执行查询的方式,比如多表连接的顺序是什么,每个表采用什么顺序去访问。

当我们面对一个执行缓慢的SQL查询时,如何快速定位问题并找到优化方案呢?这时,MySQL的EXPLAIN命令就派上了用场。EXPLAIN是MySQL提供的一个分析查询的工具,它可以帮助我们分析SQL查询语句的性能瓶颈,以便我们进行针对性的优化。通过在查询语句前加上EXPLAIN关键字,MySQL会返回查询的执行计划,包括查询的每一步是如何进行的,以及是否使用了索引等信息。

EXPLAIN的使用方法

使用EXPLAIN命令非常简单,只需要在需要分析的SQL语句前加上EXPLAIN关键字就可以啦。例如:

EXPLAIN SELECT * FROM users WHERE username = 'JohnDoe';

 执行上述命令后,MySQL会返回查询的执行计划。 

注意:

EXPLAIN不会考虑Cache

EXPLAIN不可以显示在执行查询时候所作的各种优化工作

EXPLAIN不能告诉你关于触发器,存储过程的信息或者用户自定义函数对查询的影响情况 

EXPlAIN结果解读

  1. id:查询的标识符,每个SELECT(或子查询)都有一个唯一的标识符。
  2. select_type:查询的类型(SIMPLE、SUBQUERY、UNION等)。
  3. table:输出结果集的表。
  4. type:连接类型(system、const、eq_ref、ref、fulltext、ref_or_null、index_merge、unique_subquery、index_subquery、range、index、ALL等)。这一列非常重要,因为它表示了MySQL如何连接表。通常,我们希望看到的结果是constrefrangeindex,而不是ALL(全表扫描)。
  5. possible_keys:可能应用在这张表上的索引。注意这只是可能,并不一定会真正使用。
  6. key:实际使用的索引。如果没有使用索引,则显示为NULL。
  7. key_len:使用的索引的长度。在不使用所有的索引列的情况下,可以决定使用的长度。
  8. ref:显示哪些列或常量被用作索引查找上的条件。
  9. rows:MySQL估计为了找到所需的行而要检查的行数。注意,这只是一个估计值,并不总是准确的。
  10. Extra:包含MySQL解决查询的详细信息。这一列包含的信息非常丰富,如“Using where”、“Using temporary”、“Using filesort”等,这些都可以帮助我们更好地理解查询的执行过程。

详情介绍

1. id
  • 描述:查询的标识符,每个SELECT(或子查询)都有一个唯一的标识符。
  • 作用:帮助识别查询中的子查询和它们的执行顺序。
2. select_type
  • 描述:查询的类型,标识了查询的来源。
  • 类型及含义
    • SIMPLE:不包含子查询或UNION的简单SELECT查询。
    • PRIMARY:最外层的SELECT查询。
    • DERIVED:以FROM子句中的子查询方式出现的SELECT语句。
    • UNION:UNION中的第二个或之后的SELECT查询。
    • UNION RESULT:从UNION的结果集中获取数据的SELECT查询。
    • SUBQUERY:不在FROM子句中出现的子查询,通常在SELECT语句中使用。
    • DEPENDENT SUBQUERY:子查询依赖外层查询的结果集。
3. table

4. type

5. possible_keys

6. key

7. key_len

8. ref

9. rows

10. Extra

  • 描述:输出结果集的表。
  • 作用:显示查询涉及的表。
  • 描述:连接类型,表示MySQL如何连接表。
  • 类型及含义
    • system:表只有一行(等于const)。
    • const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次!
    • eq_ref:所有部分都使用了唯一索引或主键。
    • ref:所有部分都使用了非唯一索引或唯一索引的非唯一前缀。
    • fulltext:使用全文索引。
    • ref_or_null:与ref类似,但是包含了mysql对NULL的搜索。
    • index_merge:表示使用了索引合并优化方法。
    • unique_subquery:用于IN子查询,该子查询返回一个唯一值。
    • index_subquery:与unique_subquery类似,但是它返回非唯一值。
    • range:对索引进行范围检索。
    • index:全索引扫描,意味着MySQL将扫描整个索引来查找匹配的行。
    • ALL:全表扫描,意味着MySQL需要扫描整张表来找到匹配的行。
  • 描述:可能应用在这张表上的索引。
  • 作用:显示可能应用在这张表上的索引,注意是可能,并不一定会真正使用。
  • 描述:实际使用的索引。
  • 作用:显示MySQL决定使用的索引。
  • 描述:使用的索引的长度。
  • 作用:在不使用所有的索引列的情况下,可以决定使用的长度。
  • 描述:显示哪些列或常量被用作索引查找上的条件。
  • 作用:帮助理解索引是如何被使用的。
  • 描述:MySQL估计为了找到所需的行而要检查的行数。
  • 作用:虽然是估计值,但可以作为优化查询的一个参考。
  • 描述:包含MySQL解决查询的详细信息。
  • 作用:提供了查询执行过程中的额外信息,如是否使用了WHERE子句、是否使用了临时表、是否进行了文件排序等。

如何使用EXPLAIN进行优化?

  1. 避免全表扫描:通过优化查询条件,尽量使MySQL能够使用索引来查询数据,而不是进行全表扫描。
  2. 优化索引:根据查询的需求,合理设计索引,避免冗余的索引或不必要的索引。
  3. 优化查询语句:尽量避免在查询语句中使用复杂的嵌套子查询或JOIN操作,这些都会增加查询的复杂度。
  4. 使用LIMIT限制返回结果集:当只需要返回部分结果时,使用LIMIT可以显著减少MySQL需要处理的行数。
  5. 定期维护数据库:通过定期更新统计信息、重建索引等操作,保持数据库的性能。

下一章讲解如何优化SQL查询

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

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

相关文章

iOS 其他应用的文件如何在分享中使用自己的应用打开

废话少说 一、第一步:先配置好plist文件 右击info.plist如下图文件打开 根据自己需要配置支持的文件类型,也可使用property List中配置,一样的 其他的文件可是参考文档:System-Declared Uniform Type Identifiers 可复制的代码&am…

我只有一点Python基础,对学习WebGIS开发有帮助吗?

经常有人后台私信问,我只有一点Python基础,对学习GIS开发有帮助吗? 关于这个问题的答案是,当然有!Python适用于WebGIS开发。WebGIS是地理信息系统(GIS)技术与Web技术的结合,而Pytho…

第1章 框架学习的基石与实战策略

第1章框架学习的基石与实战策略 1.1 框架学习的引路人:权威教程的重要性 在编程的世界里,掌握一个框架就像是装备了一套精良的工具,这不仅能显著提升开发速度,还能展现一个程序员的专业水平。对于那些刚刚踏入编程领域的初学者来…

使用sorted对字典排序

有时我们需要按照字典数据的键值对进行排序,这个时候就可以用到sorted函数。 import operator dic{"testA":3,"testC":1,"testB":4,"testD":2} dicnsorted(dic.items(),keyoperator.itemgetter(0)) print(dicn) 比如我们要…

秋招Java后端开发冲刺——设计模式

本文介绍Java中的代理模式,及一些常见的模式应用。 一、Java设计模式 Java中最常见的设计模式主要有23种,如表所示: 表格:Java设计模式分类 类型设计模式创建型模式单例模式(Singleton Pattern)工厂方法…

MYSQL 四、mysql进阶 5(InnoDB数据存储结构)

一、数据库的存储结构:页 索引结构给我们提供了高效的索引方式,不过索引信息以及数据记录都是保存在文件上的,确切说时存储在页结构中,另一方面,索引是在存储引擎中实现的,Mysql服务器上的存储引擎负责对表…

Cesium 实战 - 自定义纹理材质系列之 - 动态扩散效果

Cesium 实战 - 自定义纹理材质系列之 - 动态扩散效果 核心代码完整代码在线示例Cesium 给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求; 但是作为 WebGL 引擎,肯定不够丰富,尤其是动态效果样式。 对于实体对象(Entity),可以通过自定义材质,实现各种…

World of Warcraft [CLASSIC] Level 70 Dire Maul (DM)

[月牙钥匙] [大型爆盐炸弹] World of Warcraft [CLASSIC] Level 70 厄运之槌,完美贡品,Dire Maul (DM) Foror‘s Compendium of Dragon Slaying 佛洛尔的屠龙技术纲要 因为不是兽王宝宝,而且开始位置放的不对&am…

C# —— 方法参数ref和out的作用

public static void Test(ref int a){a 10;}public static void GetValue(out int x){x 10;} ref 和 out 分别使用在方法的参数前面 ref 关键字可以使参数变成引用类型的参数, int a 10; Test(ref a); Console.WriteLine(a); 如果方法参数不加ref; 结果10&…

洛谷U389682 最大公约数合并

这道题最后有一个性质没有想出来,感觉还是有一点遗憾。 性质一、贪心是不对的 8 11 11 16虽然第一次选择8和16合并是最优的,但是如果合并两次的话8 11 11是最优的。 性质二 、有1的情况就是前k1个,也就是说,很多情况下取前k1都…

0000电子技术基础概述

数电 未来课的基础 以前是模块、器件级 现在是 系统级 价格、性能、 技术更新快速的好处:得到了实惠 坏处:工程师需要不断地学习,不变就容易out,要用发展的眼光看待问题 了解基础知识、还要有前沿概念。 理论课、实践课要相结…

CNN神经网络调参技巧

一、基本网络结构 1.若干块,每块:卷积BN激活池化 2.若干块,每块:卷积激活Dropout 3.若干块,每块:fc激活Dropout 二、技巧 1. 损失曲线 常见曲线是先快速下降后趋于平缓,如果线性下降&…

mybatisplus自带的雪花算法(IdType.ASSIGN_ID)无法自动生成弊端缺点,以及改进方法

前言 今日在使用mybatisplus的雪花算法自动给id赋值时发现怎么都是null的情况,这尼玛测了半天,终于发现巨坑,废话不多说,直接上干货 IService.save 只有调用IService中的save方法才能正常生成id,像IService.saveBatc…

Vue移动端动态表单生成组件

FormCreate 是一个可以通过 JSON 生成具有动态渲染、数据收集、验证和提交功能的表单生成组件。支持6个UI框架,适配移动端,并且支持生成任何 Vue 组件。内置20种常用表单组件和自定义组件,再复杂的表单都可以轻松搞定。 帮助文档 | 源码下载…

Day35:2734. 执行字串操作后的字典序最小字符串

Leetcode 2734. 执行字串操作后的字典序最小字符串 给你一个仅由小写英文字母组成的字符串 s 。在一步操作中,你可以完成以下行为: 选择 s 的任一非空子字符串,可能是整个字符串,接着将字符串中的每一个字符替换为英文字母表中的前…

视频技术朝着8K超高清方向发展,安防监控领域将迎来怎样变化?

一、背景 随着科技的日新月异,视频技术已逐渐成为我们日常生活中不可或缺的一部分。从娱乐、教育到安全监控,视频技术无处不在,并以其独特的方式影响着我们的生活方式。本文将探讨视频技术的发展趋势,并重点关注其在监控领域的应…

【ai】李沐 动手深度学学v2 环境安装:anaconda3、pycharm、d2

cuda-toolkit cuda_12.5.0_windows_network.exe 官方课程网站 第二版资源下载release版本 pycharm版本 李沐 【动手学深度学习v2 PyTorch版】 课程笔记 CUDA 选择11, 实际下载 12.5.0

C++里的异同点

文章目录 1. 可以在构造函数和析构函数中调用虚函数吗?2. 类对象的内存模型(内存布局)3. 菱形继承问题(钻石问题)如何解决?4. 堆和栈内存区别5. static_cast和dynamic_cast异同6. 智能指针的实现机制7. 移动…

无需劳师动众,让石油化工DCS集散控制系统轻松实现无线传输!

石油化工中,为了保证较高的可靠性和安全性,大量使用的是DCS集散控制系统。与FCS现场总线的“现场采集,转换为数字信号来集中传输”不同,DCS系统为了避免由于线缆断裂或者节点问题导致整个控制系统失灵,采用“分散传输,集中采集”的方式,即每个传感器通过4-20mA的模拟量通…

custom_evaluator.py

import numpy as np from pycocotools.cocoeval import COCOeval# 自定义COCOeval类,继承自COCOeval class CustomCOCOeval(COCOeval):# 重写computeIoU方法def computeIoU(self, imgId, catId):p self.paramsif p.useCats:gt self._gts[imgId, catId]dt self._d…