MySQL之性能剖析(三)

剖析MySQL查询

剖析单条查询

在定位到需要优化的单条查询后,可以针对查询"钻取"更多的信息,确认为什么会花费这么长的时间执行,以及需要如何去优化。不幸的是,MySQL目前大多数的测量点对于剖析查询都没有什么帮助。当然这种状况正在改善,大多数生产环境的服务器还没有使用包含最新剖析特性的版本。所以在实际应用中,除了SHOW STATUS、SHOW PROFILE、检查慢查询日志的条目(这还要求必须是Percona Server,官方MySQL版本的慢查询缺失了很多附加信息)这三种方法外就没有什么更好的办法了。

使用SHOW PROFILE

SHOW PROFILE命令是在MySQL 5.1以后的版本中引入的,来源于开源社区中的Jeremy Cole的贡献。这是唯一一个在GA版本中包含的真正的查询剖析工具。默认是禁用地,还可以通过服务器变量在会话(连接)级别动态地修改。

mysql> SELECT VERSION();
+------------+
| VERSION()  |
+------------+
| 5.7.42-log |
+------------+
1 row in set (0.11 sec)mysql> SHOW VARIABLES LIKE 'profiling';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| profiling     | OFF   |
+---------------+-------+
1 row in set (0.07 sec)mysql> SHOW PROFILE-> ;
Empty set

然后再服务器上执行的所有语句,都会测量其耗费的时间和其他一些查询执行状态变更相关的数据。这个功能有一定的作用,而且最初的设计功能更强大,但未来版本中可能会被Performance Schema所取代,尽管如此,这个工具最有用的作用还是在语句执行期间剖析服务器的具体工作。
当一条查询提交给服务器时,此工具会记录剖析信息到一张临时表,并且给查询赋予一个从1开始的整数标识符。

例子
  • 举个例子
mysql> SELECT * FROM chat_room ORDER BY id DESC LIMIT 10;
10 rows in set (0.18 sec)
mysql> SHOW PROFILES;
+----------+------------+-------------------------------------------------------+
| Query_ID | Duration   | Query                                                 |
+----------+------------+-------------------------------------------------------+
|        1 | 0.00397750 | SHOW VARIABLES LIKE 'profiling'                       |
|        2 | 0.00010750 | SELECT * FROM chat ORDER BY id DESC LIMIT 100         |
|        3 | 0.00010100 | use chat                                              |
|        4 | 0.00020625 | SELECT * FROM chat ORDER BY id DESC LIMIT 100         |
|        5 | 0.15971150 | SELECT * FROM chat_message ORDER BY id DESC LIMIT 100 |
|        6 | 0.00036200 | SELECT * FROM chat_message ORDER BY id DESC LIMIT 10  |
|        7 | 0.00037850 | SELECT * FROM chat_room ORDER BY id DESC LIMIT 10     |
+----------+------------+-------------------------------------------------------+
7 rows in set (0.17 sec)

该查询返回了10行记录,花费了0.18秒。接下来是SHOW PROFILES。
首先可以看到的是以很高的精度显示了查询的响应时间,这很好。MySQL客户端显示的时间只有两位小数,对于一些执行得很快的查询这样的精度是不够的。接下来继续看接下来的输出:


mysql> SHOW PROFILE FOR QUERY 7;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000077 |
| checking permissions | 0.000007 |
| Opening tables       | 0.000071 |
| init                 | 0.000016 |
| System lock          | 0.000006 |
| optimizing           | 0.000003 |
| statistics           | 0.000008 |
| preparing            | 0.000009 |
| Sorting result       | 0.000003 |
| executing            | 0.000002 |
| Sending data         | 0.000123 |
| end                  | 0.000004 |
| query end            | 0.000005 |
| closing tables       | 0.000005 |
| freeing items        | 0.000024 |
| cleaning up          | 0.000016 |
+----------------------+----------+
16 rows in set (0.17 sec)

剖析报告给出了查询执行的每个步骤及其花费的时间,看结果很难快速地确定哪个步骤花费地时间最多。因为输出是按照执行顺序排序,而不是按花费的时间排序的——而实际上我们更关心的是花费了多少多少时间,这样才能知道哪些开销比较打。但不幸的是无法通过诸如ORDER BY 之类的命令重新排序。假如不适用SHOW PROFILE命令而是这届查询INFORMATION_SHCEMA中对应的表,则可以按照需要格式化输出
如下方所示

mysql> SET @query_id = 7;
mysql>mysql> SELECT
STATE,
SUM( DURATION ) AS Total_R,
ROUND( 100 * SUM( DURATION ) / ( SELECT SUM( DURATION ) FROM INFORMATION_SCHEMA.PROFILING WHERE QUERY_ID = @query_id ), 2 ) AS Pct_R,
COUNT(*) AS Calls,
SUM( DURATION )/ COUNT(*) AS `R/Call`
FROM
INFORMATION_SCHEMA.PROFILING
WHERE
QUERY_ID = @query_id
GROUP BY
STATE
ORDER BY
Total_R DESC;
+----------------------+----------+-------+-------+--------------+
| STATE                | Total_R  | Pct_R | Calls | R/Call       |
+----------------------+----------+-------+-------+--------------+
| Sending data         | 0.000123 | 32.45 |     1 | 0.0001230000 |
| starting             | 0.000077 | 20.32 |     1 | 0.0000770000 |
| Opening tables       | 0.000071 | 18.73 |     1 | 0.0000710000 |
| freeing items        | 0.000024 | 6.33  |     1 | 0.0000240000 |
| init                 | 0.000016 | 4.22  |     1 | 0.0000160000 |
| cleaning up          | 0.000016 | 4.22  |     1 | 0.0000160000 |
| preparing            | 0.000009 | 2.37  |     1 | 0.0000090000 |
| statistics           | 0.000008 | 2.11  |     1 | 0.0000080000 |
| checking permissions | 0.000007 | 1.85  |     1 | 0.0000070000 |
| System lock          | 0.000006 | 1.58  |     1 | 0.0000060000 |
| closing tables       | 0.000005 | 1.32  |     1 | 0.0000050000 |
| query end            | 0.000005 | 1.32  |     1 | 0.0000050000 |
| end                  | 0.000004 | 1.06  |     1 | 0.0000040000 |
| Sorting result       | 0.000003 | 0.79  |     1 | 0.0000030000 |
| optimizing           | 0.000003 | 0.79  |     1 | 0.0000030000 |
| executing            | 0.000002 | 0.53  |     1 | 0.0000020000 |
+----------------------+----------+-------+-------+--------------+
16 rows in set (0.17 sec)

效果好多了,通过这个结果可以很容易看到查询时间太长主要是因为花了一大半的时间是"发送数据(Sending data)“,这个状态代表的原因非常多,可能是各种不同的服务器活动,包括在关联时搜索匹配的行记录等,这部分很难说能优化节省多少消耗时间。还有一种可能导致查询时间太长的原因,是数据复制到临时表这一步。如果是这种情况,则就要考虑如何改写查询以避免使用临时表,或者提升临时表的使用效率,另外还有一种状态是"结果排序()Sorting result”,如果花费的时间占比非常低。那这部分是不值得去优化的。这是一个比较典型的问题,所以一般我们都不建议用户在"优化排序缓冲区(tunning sort buffer)"或者类似的活动上花时间。
尽管剖析报告帮助我们定位到哪些活动花费了最多的时间,但并不会告诉我们为什么会这样,要弄清除为什么状态花费这么多时间,就需要深入下去,继续剖析这一步的子任务。

使用SHOW STATUS

MySQL的SHOW STATUS命令返回了一些计数器。既有服务器级别的全局计数器,也有基于某个连接的会话级别的计数器。例如其中的Queries在会话开始时为0,每提交一条查询增加1.如果执行SHOW GLOBAL STATUS(注意到新加额GLOBAL关键字),则可以查看服务器级别的从服务器启动时开始计算的查询次数统计。不同计数器的可见范围不一样,不过全局的计数器也会出现SHOW STATUS的结果中,容易被误认为时会话级别的,千万不要搞迷糊了。在使用这个命令时要注意几点,就像前面所讨论的,收集合适级别的测量值是很关键的。如果打算优化从某些特定连接观察到的东西,测量的却是全局级别的数据,就会导致胡乱.MySQL官方手册中对所有变量是会话级还是全局级做了详细的说明。
SHOW STATUS是一个有用的工具,但并不是一款剖析工具。SHOW STATUS的大部分结果都只是一个计数器,可以显示某些互动如读索引的频繁程度,但无法给出消耗了多少时间。SHOW STATUS的结果中只有一条指的是操作时间(Innodb_row_lock_time),而且只能是全局级的,所以还是无法测量绘画级别的工作。尽管SHOW STATUS无法提供基于时间的统计,但对于在执行完查询后观察某些计数器的值还是有帮助的。有时候可以猜测哪些操作代价较高或者消耗的时间较多。最有用的计数器包括句柄计数器(handler counter)、临时文件和表计数器等。下面的例子演示了如何将会话级别的计数器重置为0,然后查询前面(SHOW PROFILE)提到的视图,再检查计数器的结果

例子
  • 举个例子
mysql> FLUSH STATUS;
Query OK, 0 rows affected (0.09 sec)mysql> SELECT * FROM chat_room ORDER BY id DESC LIMIT 10;
10 rows in set (0.15 sec)
mysql> SHOW STATUS WHERE Variable_name LIKE '%Handler%' OR Variable_name LIKE 'Created%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Created_tmp_disk_tables    | 0     |
| Created_tmp_files          | 0     |
| Created_tmp_tables         | 0     |
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 2     |
| Handler_mrr_init           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 0     |
| Handler_read_key           | 1     |
| Handler_read_last          | 1     |
| Handler_read_next          | 0     |
| Handler_read_prev          | 9     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 0     |
+----------------------------+-------+
21 rows in set (0.19 sec)

从结果中可以看到Created_tmp_tables创建临时表的次数。以及读取记录的前一个指针Handler_read_prev的次数。仅从结果来推测,我们可以判断出,上面的SELECT查询在找到最新一条行记录时,通过读取前一个节点指针来获取记录的。

使用这个技术的时候,要注意SHOW STATUS本身也会创建一个临时表,而且也会通过句柄操作访问此临时表,这会影响到SHOW STATUS结果中对应的数字,而且不同的版本可能行为也不尽相同。
你可能会注意到通过EXPLAIN 查询查询的执行计划也可以获得大部分相同的信息,但EXPLAIN是通过估计得到的结果,而通过计数器则是实际的测量结果。例如EXPLAIN 无法告诉你临时表是否是磁盘表,这和内存临时表的性能差别是很大的。

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

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

相关文章

Python | Leetcode Python题解之第100题相同的树

题目: 题解: class Solution:def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:if not p and not q:return Trueif not p or not q:return Falsequeue1 collections.deque([p])queue2 collections.deque([q])while queue1 and queue2:node…

网络拓扑—FTP服务搭建

文章目录 FTP服务搭建网络拓扑配置网络FTPPC 安装FTP服务配置FTP服务FTP用户配置—1PC机访问FTP站点IE浏览器访问终端访问 FTP用户配置—2PC机访问ftp站点IE浏览器访问终端访问 FTP服务搭建 网络拓扑 //交换机忽略不计 FTP服务IP:192.168.1.1 PC机IP:19…

多级留言/评论的功能实现——Vue3前端篇

文章目录 思路分析封装组件父组件模板逻辑样式 子组件——二级留言模板逻辑样式 子组件——三级留言以上模板逻辑样式 留言组件的使用 写完论文了,来把评论的前端部分补一下。 前端的实现思路是自己摸索出来的,没找到可以符合自己需求的参考,…

windows 7 10 11快捷键到启动页面

1.快速打开用户启动文件夹 shell:startup 方式2:快速打开系统启动文件夹 shell:Common Startup shell:Common Startup

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO inline bazel增量编译

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO Theory Shared Library Symbol Conflicts (on Linux) 从左往右查找:Note that the linker only looks further down the line when looking for symbols used by but not defined in the current lib.Linux 下…

统计信号处理基础 习题解答10-4

题目: 重复习题10.3,但条件PDF变为: 以及均匀先验。如果非常大,这样先验知识很少,则会出现什么情况。 解答: 如果记 那么,根据条件独立性质,得到: 其中,&am…

linux 生成可执行文件

pip install pyinstaller pyinstaller --onefile xunhuan.py 在centos系统中,安装pyinstaller,然后执行命令,生成文件可以直接调用,比如 /root/dist/xunhuan 在/root/目录下,系统环境一般问题很大,找到…

java单元测试:使用Mockito模拟外部依赖

使用Mock对象来模拟外部依赖是单元测试中的重要技巧,特别是在你需要测试的代码依赖于外部系统(如数据库、网络服务等)时。Mock对象允许你在不实际调用这些外部系统的情况下测试代码的行为,从而提高测试的独立性和执行速度。 什么…

巧用count与count()

在C#中&#xff0c;talentInnoPfChains.Count() 和 talentInnoPfChains.Count 的性能差异主要取决于 talentInnoPfChains 的类型。这里有两种可能的情况&#xff1a; 如果 talentInnoPfChains 是一个实现了 ICollection<T> 接口的集合&#xff08;如 List<T>, Hash…

NLP与训练模型-GPT-3:探索人工智能语言生成的新纪元

在人工智能领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;一直是备受关注的研究方向之一。随着深度学习技术的发展&#xff0c;尤其是Transformer模型的出现&#xff0c;NLP领域取得了巨大的进步。其中&#xff0c;由OpenAI推出的GPT-3模型更是引起了广泛的关注和热…

SwiftUI中的组合动画(Simultaneous, Sequenced, Exclusive)

了解了常见的几种手势后&#xff0c;接下来我们了解一下组合手势的操作&#xff0c;当一个视图存在多个手势的时候&#xff0c;为了避免手势冲突&#xff0c;SwiftUI提供了自定义手势的方法&#xff0c;比如同时进行&#xff0c;顺序进行等等。 以下是一些常见的多种手势组合使…

关于AI绘画的模型、开源项目、工具、技巧的学习

目录 一、AI绘画的大模型有哪些&#xff1f; 二、Stable Diffusion是一个流行的AI绘画开源项目。 三、AI绘画的开源工具有哪些&#xff1f; 四、AI绘画的技巧 五、最简单的实践 一、AI绘画的大模型有哪些&#xff1f; AI绘画领域中存在多种大模型&#xff0c;每种模型都有…

渗透测试 一个很奇怪的支付漏洞

新手实战刷课网站、好玩又有趣&#xff01; 第一步 打开网站、任意账户名密码登陆发现验证码可重复利用 这时候我们可以试试admin账号、发现如果账号正确会提示账户已存在、反之回显账户密码错误 第二步 既然验证码可以重复利用&#xff1b;而且账号名有回显 这时候我们试…

学习使用博客记录生活

学习使用博客记录生活 新的改变 今天新的开始&#xff0c;让我用图片开始记录吧 看这个背景图片怎么样

人生苦短,我学python之数据类型(上)

个人主页&#xff1a;星纭-CSDN博客 系列文章专栏&#xff1a;Python 踏上取经路&#xff0c;比抵达灵山更重要&#xff01;一起努力一起进步&#xff01; 目录 一.元组 &#xff08;tuple&#xff09; 二.集合&#xff08;set&#xff09; 三.字典(dict) 一.元组 &#…

docker 清空所有镜像日志

Docker清空所有镜像日志流程 1. 查看当前运行的容器 首先&#xff0c;我们需要查看当前正在运行的容器&#xff0c;以确定需要清空日志的容器。 可以使用以下命令查看当前正在运行的容器&#xff1a; docker ps 1. 2. 停止所有运行中的容器 在清空镜像日志之前&#xff0c;我…

MySQL存储过程for循环处理查询结果

在MySQL数据库中&#xff0c;存储过程是一种预编译的SQL语句集&#xff0c;可以被多次调用。在MySQL中使用存储过程查询到结果后&#xff0c;有时候需要对这些结果进行循环处理。 1. 创建表 CREATE TABLE t_job (job_id int(11) unsigned NOT NULL AUTO_INCREMENT,job_name v…

深入了解银行信用卡催收系统

银行信用卡催收系统是一个专门用于管理和执行信用卡逾期账款催收工作的系统。该系统通常具备以下关键功能和特点&#xff1a; 智能呼叫系统&#xff1a;具备自动拨号功能&#xff0c;可以批量拨打逾期客户的电话&#xff0c;播放定制的催收录音信息或直接连接到人工坐席。此外…

崆峒酥饼:端午佳节的美味之选

崆峒酥饼&#xff1a;端午佳节的美味之选 在端午佳节来临之际&#xff0c;崆峒酥饼成为了备受瞩目的佳节之选。崆峒酥饼以其独特的制作工艺和口感&#xff0c;为这个传统节日增添了一份美味与温馨。 崆峒酥饼源自甘肃平凉&#xff0c;是当地的传统名点。它选用优质的面粉、油脂…