MySQL学习系列
通过上面的描述可知, 当我们通过应用程序访问 MySQL 服务时, 有时候性能不一定全部卡在语句的执行上。 当然通过慢查询日志定位那些执行效率较低的SQL 语句时候我们常用的手段, 但是:
一、 慢查询日志在查询结束以后才记录, 在应用反映执行效率出现问题的时候查询未必执行完成;
二、 有时候问题的产生不一定是语句的执行, 有可能是其他原因导致的。 慢查询日志并不能定位问题。
mysql> show processlist; +----+------+-----------+------+---------+------+-------------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+------+---------+------+-------------+------------------+ | 63 | root | localhost | NULL | Query | 0 | System lock | show processlist | +----+------+-----------+------+---------+------+-------------+------------------+ 1 row in set (0.00 sec)
这个时候通过 show processlist;查看线程状态非常有用,这可以让我们很快地了解当前 MySQL 在进行的线程,包括线程的状态、 是否锁表等, 可以实时地查看SQL 的执行情况, 同时对一些锁表操作进行优化。 在一个繁忙的服务器上, 可能会看到大量的不正常的状态, 例如 statistics 正占用大量的时间。 这通常表示, 某个地方有异常了。 线程常见的状态有很多, 比如
参考官方文档:https://dev.mysql.com/doc/refman/5.7/en/general-thread-states.html
对于每个线程到底时间花在哪里, 可以通过 show profile 来分析。
1、 首先检查当前 MySQL 是否支持 profile
mysql> select @@have_profiling; +------------------+ | @@have_profiling | +------------------+ | YES | +------------------+ 1 row in set, 1 warning (0.00 sec)
2、 默认 profiling 是关闭的, 可以通过 set 语句在 Session 级别开启 profiling:
select @@profiling; set profiling=1;
mysql> select @@profiling; +-------------+ | @@profiling | +-------------+ | 0 | +-------------+ 1 row in set, 1 warning (0.00 sec) mysql> set profiling=1; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select @@profiling; +-------------+ | @@profiling | +-------------+ | 1 | +-------------+ 1 row in set, 1 warning (0.00 sec)
3、 执行一个 SQL 查询
select count(*) from order_exp;
4、 通过 show profiles 语句, 看到当前 SQL 的 Query ID
show profiles;
mysql> use test; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select count(*) from order_exp; +----------+ | count(*) | +----------+ | 10567 | +----------+ 1 row in set (0.01 sec) mysql> show profiles; +----------+------------+--------------------------------+ | Query_ID | Duration | Query | +----------+------------+--------------------------------+ | 1 | 0.00034400 | select @@profiling | | 2 | 0.00023950 | select count(*) from order_exp | | 3 | 0.00050475 | SELECT DATABASE() | | 4 | 0.00095700 | show databases | | 5 | 0.00055825 | show tables | | 6 | 0.00665250 | select count(*) from order_exp | +----------+------------+--------------------------------+ 6 rows in set, 1 warning (0.00 sec)
5、 通过 show profile for query 语句能够看到执行过程中线程的每个状态和消
耗的时间
show profile for query 6;
mysql> show profile for query 6; +----------------------+----------+ | Status | Duration | +----------------------+----------+ | starting | 0.000171 | | Opening tables | 0.000030 | | System lock | 0.000112 | | checking permissions | 0.000016 | | Opening tables | 0.000029 | | init | 0.000067 | | System lock | 0.000025 | | optimizing | 0.000077 | | statistics | 0.000031 | | preparing | 0.000023 | | executing | 0.000009 | | Sending data | 0.005908 | | end | 0.000025 | | query end | 0.000032 | | closing tables | 0.000019 | | freeing items | 0.000049 | | cleaning up | 0.000031 | +----------------------+----------+ 17 rows in set, 1 warning (0.02 sec)
通过仔细检查 show profile for query 的输出, 能够发现在执行 COUNT(*)的过程中, 时间主要消耗在 Sending data 这个状态上。
6、 在获取到最消耗时间的线程状态后, MySQL 支持进一步选择 all、 cpu、block io、 contextswitch、 page faults 等明细类型来查看 MySQL 在使用什么资源上耗费了过高的时间:
show profile all for query 6\G
mysql> show profile all for query 6\G *************************** 1. row *************************** Status: starting Duration: 0.000171 CPU_user: 0.000000 CPU_system: 0.000164 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: NULL Source_file: NULL Source_line: NULL *************************** 2. row *************************** Status: Opening tables Duration: 0.000030 CPU_user: 0.000000 CPU_system: 0.000030 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: open_ltable Source_file: sql_base.cc Source_line: 6490 *************************** 3. row *************************** Status: System lock Duration: 0.000112 CPU_user: 0.000013 CPU_system: 0.000099 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: mysql_lock_tables Source_file: lock.cc Source_line: 330 *************************** 4. row *************************** Status: checking permissions Duration: 0.000016 CPU_user: 0.000007 CPU_system: 0.000009 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: check_access Source_file: sql_authorization.cc Source_line: 809 *************************** 5. row *************************** Status: Opening tables Duration: 0.000029 CPU_user: 0.000012 CPU_system: 0.000017 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: open_tables Source_file: sql_base.cc Source_line: 5815 *************************** 6. row *************************** Status: init Duration: 0.000067 CPU_user: 0.000028 CPU_system: 0.000039 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: handle_query Source_file: sql_select.cc Source_line: 128 *************************** 7. row *************************** Status: System lock Duration: 0.000025 CPU_user: 0.000000 CPU_system: 0.000084 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: mysql_lock_tables Source_file: lock.cc Source_line: 330 *************************** 8. row *************************** Status: optimizing Duration: 0.000077 CPU_user: 0.000000 CPU_system: 0.000018 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: optimize Source_file: sql_optimizer.cc Source_line: 158 *************************** 9. row *************************** Status: statistics Duration: 0.000031 CPU_user: 0.000000 CPU_system: 0.000030 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: optimize Source_file: sql_optimizer.cc Source_line: 374 *************************** 10. row *************************** Status: preparing Duration: 0.000023 CPU_user: 0.000000 CPU_system: 0.000023 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: optimize Source_file: sql_optimizer.cc Source_line: 482 *************************** 11. row *************************** Status: executing Duration: 0.000009 CPU_user: 0.000000 CPU_system: 0.000010 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: exec Source_file: sql_executor.cc Source_line: 126 *************************** 12. row *************************** Status: Sending data Duration: 0.005908 CPU_user: 0.005915 CPU_system: 0.000000 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 1 Swaps: 0 Source_function: exec Source_file: sql_executor.cc Source_line: 202 *************************** 13. row *************************** Status: end Duration: 0.000025 CPU_user: 0.000018 CPU_system: 0.000000 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: handle_query Source_file: sql_select.cc Source_line: 206 *************************** 14. row *************************** Status: query end Duration: 0.000032 CPU_user: 0.000031 CPU_system: 0.000000 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: mysql_execute_command Source_file: sql_parse.cc Source_line: 4959 *************************** 15. row *************************** Status: closing tables Duration: 0.000019 CPU_user: 0.000018 CPU_system: 0.000000 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: mysql_execute_command Source_file: sql_parse.cc Source_line: 5018 *************************** 16. row *************************** Status: freeing items Duration: 0.000049 CPU_user: 0.000050 CPU_system: 0.000000 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: mysql_parse Source_file: sql_parse.cc Source_line: 5637 *************************** 17. row *************************** Status: cleaning up Duration: 0.000031 CPU_user: 0.000030 CPU_system: 0.000000 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 0 Swaps: 0 Source_function: dispatch_command Source_file: sql_parse.cc Source_line: 1933 17 rows in set, 1 warning (0.00 sec)
其中
*************************** 12. row *************************** Status: Sending data Duration: 0.005908 CPU_user: 0.005915 CPU_system: 0.000000 Context_voluntary: 0 Context_involuntary: 0 Block_ops_in: 0 Block_ops_out: 0 Messages_sent: 0 Messages_received: 0 Page_faults_major: 0 Page_faults_minor: 1 Swaps: 0 Source_function: exec Source_file: sql_executor.cc Source_line: 202
能够发现 Sending data 状态下, 时间主要消耗在 CPU 上了。所以show profile能够在做SQL优化时帮助我们了解时间都耗费到哪里去了,同时如果 MySQL 源码感兴趣, 还可以通过 show profile source for query 查看 SQL解析执行过程中每个步骤对应的源码的文件、 函数名以及具体的源文件行数。