mysql5.7全局考虑性能化,SQL优化的最后一步:profile性能分析

一、JDBC

setResultSetType(ResultSet.TYPE_FORWARD_ONLY);   告诉mysql发送流数据过来

setFetchSize(1000);      告诉mysql获取条数

拿部分数据过来,直到把所有数据都处理完毕。

用游标也可以。

但上述用游标或者流的方式,都是把压力都转嫁给了mysql,mysql会开辟一个内存出来去放结果集,对mysql而言,会产生极大的压力。那可以考虑比如手动在java层做分页。

二、线程繁忙原因

有时候mysql在执行某SQL时遇上线程繁忙,mysql对于线程状态有细致规定: https://dev.mysql.com/doc/refman/5.7/en/general-thread-states.html 

【statistics】 统计。线程正在统计信息以研究查询执行计划。如果线程长时间处于这个状态,意味着这个线程可能被别的磁盘IO占用了。

【Creating tmp table】创建临时表。正在创建一个内存中或磁盘中的临时表,如果刚开始创建的是内存临时表,后来改为创建磁盘临时表,则状态会变为“Coping to tmp table on disk”

我们可以使用 show processlist;   来查看线程处于什么状态:

三、profile性能分析

mysql> select @@have_profiling;   -- 查看是否支持profile
+------------------+
| @@have_profiling |
+------------------+
| YES              |
+------------------+
1 row in set (0.02 sec)

开启profile:

mysql> select @@profiling;  -- 如果支持profile的话,那么查看是否开启了profile, 默认是0不开启,可以通过  set profiling=1; 设置为session级别的开启
+-------------+
| @@profiling |
+-------------+
|           0 |
+-------------+
1 row in set (0.02 sec)

这时候执行一个sql:   SELECT * FROM t_user WHERE address in ('shanghaishi', 'beijingshi', 'wenzhoushi');   结果集大约有8654条数据。再用  show profiles;  命令去看刚才那个SQL的执行耗时情况:

mysql> show profiles;
+----------+------------+-----------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                             |
+----------+------------+-----------------------------------------------------------------------------------+
|        1 | 0.00036600 | select @@profiling                                                                |
|        2 | 0.01598275 | select count(*) from t_user                                                       |
|        3 | 0.02613600 | SELECT * FROM t_user WHERE address in ('shanghaishi', 'beijingshi', 'wenzhoushi') |
+----------+------------+-----------------------------------------------------------------------------------+
3 rows in set (0.05 sec)

记住这里的Query_ID是3,然后     show profile for query 3;

mysql> show profile for query 3;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000061 |
| checking permissions | 0.000010 |
| checking permissions | 0.000004 |
| Opening tables       | 0.000018 |
| init                 | 0.000075 |
| System lock          | 0.000011 |
| optimizing           | 0.000014 |
| statistics           | 0.000167 |
| preparing            | 0.000038 |
| executing            | 0.000005 |
| Sending data         | 0.025582 |
| end                  | 0.000012 |
| query end            | 0.000007 |
| closing tables       | 0.000008 |
| freeing items        | 0.000041 |
| logging slow query   | 0.000072 |
| cleaning up          | 0.000013 |
+----------------------+----------+
17 rows in set (0.05 sec)

以上表示在整个sql的生命周期中,每个阶段的耗时,可以看到耗时最长的环节是 Sending data,  想知道每个环节是什么意思,可以去mysql官网( https://dev.mysql.com/doc/refman/5.7/en/general-thread-states.html )查线程状态,比如Sending data, mysql官网是这么定义的:

翻译过来就是:该线程正在读取和处理 SELECT 语句所检索出来的行,并将数据发送到客户端。由于在此状态期间发生的操作往往会执行大量磁盘访问(读取),因此它通常是给定查询生命周期中运行时间最长的状态。

如果想知道更加具体的Sending data到底慢在cpu? 还是IO?还是其他什么地方,可以使用 show profile all for query 3;     

从以上结果集可以看出,大部分时间都花在CPU上。

彩蛋:如果你对mysql的源码感兴趣,可以使用show profile source for query 3;   可以看到具体每个操作定位到mysql源码的哪一行。

end.

 

posted on 2021-07-19 20:59  梦幻朵颜  阅读(305)  评论(0编辑  收藏  举报