《MySQL高级篇》七、性能分析工具的使用(慢查询日志 | EXPLAIN | SHOW PROFILING | 视图分析 )(二)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 《MySQL高级篇》七、性能分析工具的使用(慢查询日志 | EXPLAIN | SHOW PROFILING | 视图分析 )

5. 查看 SQL 执行成本:SHOW PROFILE

22ae55b626e6e1ea54578d2b08018236.png

mysql> show variables like 'profiling';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| profiling     | OFF   | #当前是关闭状态
+---------------+-------+
1 row in set (0.01 sec)
mysql> set profiling = 'ON';#开启
Query OK, 0 rows affected, 1 warning (0.00 sec)

然后执行相关的查询语句。接着看下当前会话下有哪些profiles

mysql> SELECT * FROM student WHERE stuno = 3455655;
//...
mysql> SELECT * FROM student WHERE name = 'ZfCwDz';
//...
mysql> show profiles;
+----------+------------+---------------------------------------------+
| Query_ID | Duration   | Query                                       |
+----------+------------+---------------------------------------------+
|        1 | 0.00133475 | show variables like 'profiling'             |
|        2 | 0.00021050 | SELECT * FROM student WHERE stuno = 3455655 |
|        3 | 0.00053600 | SELECT DATABASE()                           |
|        4 | 0.01693325 | show databases                              |
|        5 | 0.00375125 | show tables                                 |
|        6 | 1.75597875 | SELECT * FROM student WHERE stuno = 3455655 |
|        7 | 1.11115150 | SELECT * FROM student WHERE name = 'ZfCwDz' |
+----------+------------+---------------------------------------------+
7 rows in set, 1 warning (0.00 sec)

你能看到当前会话一共有7个查询,如果我们想要查看最近一次查询的开销,可以使用

show profile;

1a208a75a95c6b3b4b70bb5111a87b1d.png

我们也可以查看指定的Query ID的开销,只需要后面跟上 for num。也可以查看不同部分的开销,比如CPU、block.io等

show profile cpu,block io for query 7;

b05a9a0b095cd2b2496295c622fdf402.png


通过如果发现上一条 sql 慢的原因在于执行慢(executing字段耗时多),就可以接着用 Explain 进行分析具体的 sql 语句。等后面我们为其建立索引,就可以大大提高效率了


🔊 show profile的常用查询参数:


① ALL:显示所有的开销信息。

② BLOCK IO:显示块 IO 开销。

③ CONTEXT SWITCHES:上下文切换开销。

④ CPU:显示 CPU 开销信息。

⑤ IPC:显示发送和接收开销信息。

⑥ MEMORY:显示内存开销信息。

⑦ PAGE FAULTS:显示页面错误开销信息。

⑧ SOURCE:显示和 Source_function,Source_file,Source_line 相关的开销信息。

⑨ SWAPS:显示交换次数开销信息。


🎨 日常开发需要注意的结论:


① Coverting Heap to MyISAM:查询结果太大,内存不够,正在往磁盘中迁移

② Creating tmp table:创建临时表,先拷贝数据到临时表,用完再删除临时表

③Coping to tmp table on disk:把内存中临时表复制到磁盘上,警惕!

④ locked


如果在 show profile 的查询结果中,出现了以上4条结果中的任何一条。则sql 语句需要优化


最后,还需要注意:


SHOW PROFILE 命令将被弃用,不过我们可以从 information_schema 中的 profiling 数据表进行查看


6. 分析查询语句:EXPLAIN(重点)


6.1 EXPLAIN 概述


0f20ee3121dfd0daee25ee3ba1db8b43.png


https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

https://dev.mysql.com/doc/refman/8.0/en/explain-output.html


de7fcc7b8dbf7185f725b3005b5dca59.png


3. 版本情况


MySQL 5.6.3以前只能EXPLAIN SELECT ;MYSQL 5.6.3以后就可以EXPLAIN SELECT,UPDATE,DELETE


在5.7以前的版本中,想要显示partitions 需要使用explain partitions命令;想要显示

filtered 需要使用explain extended 命令。在5.7版本后,默认explain直接显示partitions和

filtered中的信息


76dca21873abe282bc211d8ebd1acf87.png


注意:EXPLAIN 仅仅是查看执行计划,不会真实的执行 sql


6.2 基本语法


EXPLAIN 或 DESCRIBE语句的语法形式如下:

EXPLAIN SELECT select_options
或者
DESCRIBE SELECT select_options

如果我们想看看某个查询的执行计划的话,可以在具体的查询语句前边加一个EXPLAIN ,就像这样:

mysql> EXPLAIN SELECT 1;


9a5762c760918391af90e5a10af5c529.png


7e286d10ad9a06464f4911aa5505bb79.png

EXPLAIN 语句输出的各个列的作用如下:


6f96464bb4a6d101534a0b93e49741b5.png

在这里把它们都列出来只是为了描述一个轮廓,让大家有一个大致的印象。

6.3 数据准备

1. 建表

CREATE TABLE s1 (
     id INT AUTO_INCREMENT,
     key1 VARCHAR(100),
     key2 INT,
     key3 VARCHAR(100),
     key_part1 VARCHAR(100),
     key_part2 VARCHAR(100),
     key_part3 VARCHAR(100),
     common_field VARCHAR(100),
      PRIMARY KEY (id),
      INDEX idx_key1 (key1),
      UNIQUE INDEX idx_key2 (key2),
      INDEX idx_key3 (key3),
      INDEX idx_key_part(key_part1, key_part2, key_part3)
) ENGINE=INNODB CHARSET=utf8;
CREATE TABLE s2 (
     id INT AUTO_INCREMENT,
     key1 VARCHAR(100),
     key2 INT,
     key3 VARCHAR(100),
     key_part1 VARCHAR(100),
     key_part2 VARCHAR(100),
     key_part3 VARCHAR(100),
     common_field VARCHAR(100),
      PRIMARY KEY (id),
      INDEX idx_key1 (key1),
      UNIQUE INDEX idx_key2 (key2),
      INDEX idx_key3 (key3),
      INDEX idx_key_part(key_part1, key_part2, key_part3)
) ENGINE=INNODB CHARSET=utf8;

注:建两个表方便联合查询

2. 创建存储函数

DELIMITER 
CREATE FUNCTION rand_string1(n INT)
    RETURNS VARCHAR(255) #该函数会返回一个字符串
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
    DECLARE return_str VARCHAR(255) DEFAULT '';
    DECLARE i INT DEFAULT 0;
    WHILE i < n DO
        SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
        SET i = i + 1;
    END WHILE;
    RETURN return_str;
END 
DELIMITER ;

创建函数,假如报错,需设置参数 log_bin_trust_function_creators,允许创建函数设置

set global log_bin_trust_function_creators=1;   # 不加global只是当前窗口有效。

3. 创建存储过程

创建往 s1 表中插入数据的存储过程:

DELIMITER //
CREATE PROCEDURE insert_s1 (IN min_num INT (10),IN max_num INT (10))
BEGIN
    DECLARE i INT DEFAULT 0;
    SET autocommit = 0;
    REPEAT
    SET i = i + 1;
    INSERT INTO s1 VALUES(
     (min_num + i),
     rand_string1(6),
     (min_num + 30 * i + 5),
     rand_string1(6),
     rand_string1(10),
     rand_string1(5),
     rand_string1(10),
     rand_string1(10));
    UNTIL i = max_num
    END REPEAT;
    COMMIT;
END //
DELIMITER ;

创建往 s2 表中插入数据的存储过程:

DELIMITER //
CREATE PROCEDURE insert_s2 (IN min_num INT (10),IN max_num INT (10))
BEGIN
    DECLARE i INT DEFAULT 0;
    SET autocommit = 0;
    REPEAT
    SET i = i + 1;
    INSERT INTO s2 VALUES((min_num + i),
        rand_string1(6),
        (min_num + 30 * i + 5),
        rand_string1(6),
        rand_string1(10),
        rand_string1(5),
        rand_string1(10),
        rand_string1(10));
    UNTIL i = max_num
    END REPEAT;
    COMMIT;
END //
DELIMITER ;

4. 调用存储过程

s1 表数据的添加:加入 1 万条记录:

CALL insert_s1(10001,10000);

s2 表数据的添加:加入 1 万条记录:

CALL insert_s2(10001,10000);


6.4 EXPLAIN 各列作用

为了让大家有比较好的体验,我们调整了下EXPLAIN输出列的顺序。

6.4.1 table


不论我们的查询语句有多复杂,里边儿包含了多少个表 ,到最后也是需要对每个表进行单表访问的,所以 MySQL 规定 EXPLAIN 语句输出的每条记录都对应着某个单表的访问方法,该条记录的 table 列代表着该表的表名(有时不是真实的表名字,可能是简称)。


EXPLAIN SELECT * FROM s1 INNER JOIN s2;

如下图,一张表对应一个记录

7422bfdc6cf19b57ded5f4254ee65e35.png


注:临时表也会有对应的记录,比如我们使用UNION时就会出现临时表

6.4.2 id

例1:下面的查询结果,两个记录似乎id都是1.这是为什么呢?


81e902a5c7c9b5f221123284878eb8fa.png

实际上,在查询语句中每出现一个SELECT关键字,MySQL就会为它分配一个唯一的id ,代表着一次查询。这个id 就是 EXPLAIN语句的第一列。

例2:下面的查询中只有一个SELECT,所以EXPLAIN的结果中也就只有一条id为 1 的记录喽~


4ef38bf5e4227c4d210bbe65b1795fee.png

例3:下面的查询有两个SELECT,所以EXPLAIN的结果中 会有两条记录,且id分别就是1和2喽~ 。其中 s1被称为驱动表,s2被称为 被驱动表

fc6d95febc423e95d0260b14a944808d.png


例4:下面这条SQL有一个坑,请注意!!!

EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key2 FROM s2 WHERE common_field = 'a');


两个记录的 id 都是 1,小小的眼睛是否充满了大大的疑惑?

f8df290a5abe558b37d4d2d30214511a.png

这是因为优化器会对上面的 sql 语句进行优化,将其转换为多表连接,而不是子查询。因为子查询其实是一种嵌套查询的情况,其时间复杂度是 O(n^m),其中 m 是嵌套的层数,而多表查询的时间复杂度是 O(n*m)


例5:再看看 Union 联合查询的情况。

EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;


结果是这样,竟然会出现三张表~ Amazing!

839dcd890063ae9e8bee825a692ee3a0.png

这是因为 Union 是取表的并集,需要建临时表进行去重,因此会有三条记录。可以看到第三条记录的 Extra 就标识了它是一张临时表哦。临时表 id 是 Null


例6:再看看 Union ALL:

EXPLAIN SELECT * FROM s1  UNION ALL SELECT * FROM s2;


产生两条记录,因为它不会去重~

19c7755d36ff35764187600cbcc8a589.png

💌小结

  1. id如果相同,可以认为是一组,从上往下顺序执行
  2. 在所有组中,id值越大,优先级越高,越先执行
  3. 关注点:id号每个号码,表示一趟独立的查询, 一个sql的查询趟数越少越好




相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
1月前
|
存储 消息中间件 监控
MySQL 到 ClickHouse 明细分析链路改造:数据校验、补偿与延迟治理
蒋星熠Jaxonic,数据领域技术深耕者。擅长MySQL到ClickHouse链路改造,精通实时同步、数据校验与延迟治理,致力于构建高性能、高一致性的数据架构体系。
MySQL 到 ClickHouse 明细分析链路改造:数据校验、补偿与延迟治理
|
2月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
128 3
|
1月前
|
NoSQL 算法 Redis
【Docker】(3)学习Docker中 镜像与容器数据卷、映射关系!手把手带你安装 MySql主从同步 和 Redis三主三从集群!并且进行主从切换与扩容操作,还有分析 哈希分区 等知识点!
Union文件系统(UnionFS)是一种**分层、轻量级并且高性能的文件系统**,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem) Union 文件系统是 Docker 镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
333 5
|
2月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(上)
最终建议:当前系统是完美的读密集型负载模型,优化重点应放在减少行读取量和提高数据定位效率。通过索引优化、分区策略和内存缓存,预期可降低30%的CPU负载,同时保持100%的缓冲池命中率。建议每百万次查询后刷新统计信息以持续优化
213 6
|
2月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(中)
使用MYSQL Report分析数据库性能
141 1
|
监控 Java 开发者
Java一分钟之-Java性能分析与调优:JProfiler, VisualVM等工具
【5月更文挑战第21天】本文介绍了Java性能优化的两个利器——JProfiler和VisualVM。JProfiler通过CPU Profiler、内存分析器和线程视图帮助解决过度CPU使用、内存泄漏和线程阻塞问题;VisualVM则聚焦于GC行为调整和类加载优化,以减少内存压力和提高应用性能。使用这些工具进行定期性能检查,是提升Java应用效率的关键。
477 0
|
缓存 监控 Linux
Linux性能分析利器:全面掌握perf工具
【10月更文挑战第18天】 在Linux系统中,性能分析是确保软件运行效率的关键步骤。`perf`工具,作为Linux内核自带的性能分析工具,为开发者提供了强大的性能监控和分析能力。本文将全面介绍`perf`工具的使用,帮助你成为性能优化的高手。
754 1
|
缓存 监控 Linux
掌握Linux性能分析:深入探索perf工具
【10月更文挑战第26天】
590 1
|
SQL 缓存 关系型数据库
MySQL高级篇——性能分析工具
MySQL的慢查询日志,用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long-query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为 10,意思是运行10秒以上(不含10秒)的语句,认为是超出了我们的最大忍耐时间值。它的主要作用是,帮助我们发现那些执行时间特别长的 SOL 查询,并且有针对性地进行优化,从而提高系统的整体效率。当我们的数据库服务器发生阻塞、运行变慢的时候,检查一下慢查询日志,找到那些慢查询,对解决问题很有帮助。
MySQL高级篇——性能分析工具
|
Web App开发 监控 JavaScript
一些常用的 Vue 性能分析工具
【10月更文挑战第2天】
775 1

推荐镜像

更多
下一篇
oss云网关配置