zoukankan      html  css  js  c++  java
  • 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是通过估计得到的结果,而通过计数器则是实际的测量结果.

     

  • 相关阅读:
    Cookie
    servletContext组件
    Servlet的定义及生命周期
    导引:servlet&Jsp的经典模式
    一个servlet server,由移植自Tomcat的连接器模块和自编写的container模块代码组成
    一个servlet web server,由移植自Tomcat的完整的connector模块和简化的Container(取代servlet处理器)组成
    python初识
    Maekdown光速习得
    实例学习——爬取简书网用户动态
    使用CSDN-markdown编辑器粘贴代码块时崩溃问题解决
  • 原文地址:https://www.cnblogs.com/david-rui/p/3517643.html
Copyright © 2011-2022 走看看