Mysql剖析单条查询(高性能mySql学习笔记)
Mysql剖析单条查询的方法: (以mysql官网提供的sakila数据库演示)
方式1.通过show profile工具(show profile是Mysql5.1版本之后引入的功能)
工作原理:show profile是一个工具, 当一条查询提交给服务器时,该工具会将记录剖析信息到一张临时表,并且给查询赋予一个从1开始的整数标志符.
使用举例:
Mysql> SET profiling=1; (默认是禁用的)
Mysql>SELECT * from sakila.nicer_but_slower_film_list;
Mysql> show profiles;
+----------+------------+--------------------------------------------------+
| Query_ID | Duration |
Query
|
+----------+------------+--------------------------------------------------+
| 1 | 0.12766825 | SELECT *
from sakila.nicer_but_slower_film_list |
+----------+------------+--------------------------------------------------+
可以看到该语句执行时间,但是不够详细,此时可以使用 show profile for query queryId进一步查看更加详细的
mysql> show profile for query 1; +----------------------+----------+ | Status | Duration | +----------------------+----------+ | starting | 7.5E-5 | | checking permissions | 5E-6 | | Opening tables | 0.000431 | | System lock | 1.5E-5 | | checking permissions | 2E-6 | | checking permissions | 2E-6 | | checking permissions | 1E-6 | | checking permissions | 1E-6 | | checking permissions | 0.002143 | | optimizing | 1.6E-5 | | statistics | 7.3E-5 | | preparing | 1.8E-5 | | Creating tmp table | 0.001932 | | executing | 4E-6 | | Copying to tmp table | 0.052056 | | Sorting result | 0.008785 | | Sending data | 0.05388 | | removing tmp table | 0.002344 | | Sending data | 1.3E-5 | | init | 1.8E-5 | | optimizing | 4E-6 | | statistics | 8E-6 | | preparing | 1E-5 | | executing | 1E-6 | | Sending data | 0.003856 | | end | 9E-6 | | query end | 5E-6 | | closing tables | 2E-6 | | removing tmp table | 0.001827 | | closing tables | 1.8E-5 | | freeing items | 1.3E-5 | | removing tmp table | 7E-6 | | freeing items | 9E-5 | | logging slow query | 3E-6 | | cleaning up | 5E-6 | +----------------------+----------+ 35 rows in set
这个剖析报告给出了查询中每个步骤所花费的时间,但是这个报告是按照执行顺序进行排序的,但是我们更多的是关注花费时间最多的步骤, 此时我们如果不用show profile命令,还可以查询information_schema.PROFILING表
Mysql>SET @query_id = 9;
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.053959 | 44.97 | 3 | 0.0179863333 | | Copying to tmp table | 0.048336 | 40.29 | 1 | 0.0483360000 | | Sorting result | 0.008770 | 7.31 | 1 | 0.0087700000 | | removing tmp table | 0.004025 | 3.35 | 3 | 0.0013416667 | | checking permissions | 0.002216 | 1.85 | 6 | 0.0003693333 | | Creating tmp table | 0.001866 | 1.56 | 1 | 0.0018660000 | | Opening tables | 0.000437 | 0.36 | 1 | 0.0004370000 | | freeing items | 0.000094 | 0.08 | 2 | 0.0000470000 | | starting | 0.000079 | 0.07 | 1 | 0.0000790000 | | statistics | 0.000072 | 0.06 | 2 | 0.0000360000 | | preparing | 0.000022 | 0.02 | 2 | 0.0000110000 | | optimizing | 0.000021 | 0.02 | 2 | 0.0000105000 | | System lock | 0.000020 | 0.02 | 1 | 0.0000200000 | | closing tables | 0.000018 | 0.02 | 2 | 0.0000090000 | | init | 0.000016 | 0.01 | 1 | 0.0000160000 | | end | 0.000008 | 0.01 | 1 | 0.0000080000 | | executing | 0.000006 | 0.01 | 2 | 0.0000030000 | | query end | 0.000004 | 0.00 | 1 | 0.0000040000 | | cleaning up | 0.000004 | 0.00 | 1 | 0.0000040000 | | logging slow query | 0.000003 | 0.00 | 1 | 0.0000030000 |
从这个结果可以看到,sending data和Copying to tmp table花费时间最多,就可以进一步分析优化了.
方式2.通过show status方式剖析单条查询
原理:
show
status大部分结果都只是一个计数器,可以显示某些活动如读索引的频繁程度,但无法给出消耗了多长时间.
尽管show
status无法提供基于时间的统计,但是执行完成后观察执行结果,还是 有帮助的,最有用的计数器包括:
句柄计数器(handler
counter),临时文件,表计数器
我们可以通过将会话级别的计数器清零,然后查询前面的视图,再检查计数器结果
mysql> FLUSH statu; mysql> SELECT * from nicer_but_slower_film_list; mysql> show status where Variable_name like ‘Handler%‘ or Variable_name Like ‘Created%‘; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Created_tmp_disk_tables | 10 | | Created_tmp_files | 5 | | Created_tmp_tables | 28 | | Handler_commit | 5 | | Handler_delete | 0 | | Handler_discover | 0 | | Handler_prepare | 0 | | Handler_read_first | 5 | | Handler_read_key | 37425 | | Handler_read_last | 0 | | Handler_read_next | 32310 | | Handler_read_prev | 0 | | Handler_read_rnd | 27330 | | Handler_read_rnd_next | 37788 | | Handler_rollback | 0 | | Handler_savepoint | 0 | | Handler_savepoint_rollback | 0 | | Handler_update | 15 | | Handler_write | 37664 | +----------------------------+-------+
从这个结果可以看到,该查询创建了10张磁盘临时表, 而且有很多没有用到索引的多操作(Handler_read_rnd_next),假设我们不知道该视图的结构,仅从结果我们可以推测到该视图使用了多表关联查询,而且没有使用合适的索引,可能是其中一个子查询创建了临时表,和其他表做关联查询, 而保存子查询结果的临时表没有合适的索引.
注意:通过explain 命令也可以得到大部分结果,但是explain是通过估计得到的结果,而通过计数器则是实际的测量结果.
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。