一:开启慢查询日志
开启慢查询日志,配置mysql(windows系统是my.ini,linux系统是my.cnf)
log-slow-queries=mysql_slow.log
long_query_time=1
查查看配置 :show variables like "%slow_query%";
f
查看慢查询时间:show variables like "%long_query_time%";
二:查看日志
然后查看mysql安装目录下的data目录,该目录会产生一个慢查询日志文件:mysql_slow.log
慢查询日志文件的信息格式:
# Time: 130905 14:15:59 时间是2013年9月5日 14:15:59(前面部分容易看错哦,乍看以为是时间戳)
# User@Host: root[root] @ [183.239.28.174] 请求mysql服务器的客户端ip
# Query_time: 0.735883 Lock_time: 0.000078 Rows_sent: 262 Rows_examined: 262 这里表示执行用时多少秒,0.735883秒,1秒等于1000毫秒
SET timestamp=1378361759; (字面上翻译:设置时间戳)
show tables from `test_db`; 这个就是关键信息,指明了当时执行的是这条语句
三:分析慢查询(两种方式)
explain 和 desc 对 sql进行说明,描述
慢查询日志可以帮助我们把所有查询时间过长的sql语句记录下来,在优化这些语句之前,我们应该使用explain命令查看mysql的执行计划,寻找其中的可优化点。
explain命令的使用十分简单,只需要"explain + sql语句"即可,如下命令就是对我们刚刚的慢查询语句使用explain之后的结果:
mysql> explain
select
*
from
emp
where
empno=413345\G;
02.
*************************** 1. row ***************************
03.
id: 1
04.
select_type: SIMPLE
05.
table
: emp
06.
type:
ALL
07.
possible_keys:
NULL
08.
key
:
NULL
09.
key_len:
NULL
10.
ref:
NULL
11.
rows
: 10000351
12.
Extra: Using
where
13.
1 row
in
set
(0.00 sec)
14.
15.
ERROR:
16.
No
query specified
可以看到,explain命令的结果一共有以下几列:id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra,这些列分别代表以下意思:
1、id:SELECT识别符。这是SELECT的查询序列号;
2、select_type:查询类型,主要有PRIMARY(子查询中最外层查询)、SUBQUERY(子查询内层第一个SELECT)、UNION(UNION语句中第二个SELECT开始后面所有SELECT)、SIMPLE(除了子查询或者union之外的其他查询);
3、table:所访问的数据库表明;
4、type:对表的访问方式,包括以下类型all(全表扫描),index(全索引扫描),rang(索引范围扫描),ref(join语句中被驱动表索引引用查询),eq_ref(通过主键或唯一索引访问,最多只会有一条结果),const(读常量,只需读一次),system(系统表。表中只有一条数据),null(速度最快)。
5、possible_keys:查询可能使用到的索引;
6、key:最后选用的索引;
7、key_len:被选中索引的索引长度;
8、ref:列出某个表的某个字段过滤;
9、rows:估算出的结果行数;
10、extra:查询细节信息,可能是以下值:distinct、using filesort(order by操作)、using index(所查数据只需要在index中即可获取)、using temporary(使用临时表)、using where(如果包含where,且不是仅通过索引即可获取内容,就会包含此信息)。
这样,通过"explain select * from emp where empno=413345\G"命令的输出,我们就可以清楚的看到,这条查询语句是一个全表扫描语句,查询时没有用到任何索引,所以它的查询时间肯定会很慢。
四、Profiling 的使用(性能分析)
mysql除了提供explain命令用于查看命令执行计划外,还提供了profiling工具用于查看语句查询过程中的资源消耗情况。首先我们要使用以下命令开启Profiling功能:
view sourceprint?
1.
set
profiling = 1;
接下来我们执行一条查询命令:
view sourceprint?
1.
mysql>
select
*
from
emp
where
empno=413345;
2.
+
--------+--------+----------+-----+------------+---------+--------+--------+
3.
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
4.
+
--------+--------+----------+-----+------------+---------+--------+--------+
5.
| 413345 | vvOHUB | SALESMAN | 1 | 2014-10-26 | 2000.00 | 400.00 | 11 |
6.
+
--------+--------+----------+-----+------------+---------+--------+--------+
7.
1 row
in
set
(6.44 sec)
在开启了Query Profiler功能之后,MySQL就会自动记录所有执行的Query的profile信息了。 然后我们通过以下命令获取系统中保存的所有 Query 的 profile 概要信息:
view sourceprint?
01.
mysql> show profiles;
02.
+
----------+------------+--------------------------------------+
03.
| Query_ID | Duration | Query |
04.
+
----------+------------+--------------------------------------+
05.
| 1 | 0.00053000 | show tables |
06.
| 2 | 0.07412700 |
select
*
from
dept |
07.
| 3 | 0.06743300 |
select
*
from
salgrade |
08.
| 4 | 6.44056000 |
select
*
from
emp
where
empno=413345 |
09.
+
----------+------------+--------------------------------------+
10.
4
rows
in
set
(0.00 sec)
然后我们可以通过以下命令查看具体的某一次查询的profile信息:
view sourceprint?
01.
mysql> show profile cpu, block io
for
query 4;
02.
+
--------------------+----------+----------+------------+--------------+---------------+
03.
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
04.
+
--------------------+----------+----------+------------+--------------+---------------+
05.
| starting | 0.000107 | 0.000072 | 0.000025 | 0 | 0 |
06.
| Opening tables | 0.000021 | 0.000018 | 0.000003 | 0 | 0 |
07.
| System lock | 0.000006 | 0.000004 | 0.000001 | 0 | 0 |
08.
|
Table
lock | 0.000009 | 0.000008 | 0.000001 | 0 | 0 |
09.
| init | 0.000034 | 0.000033 | 0.000002 | 0 | 0 |
10.
| optimizing | 0.000012 | 0.000011 | 0.000001 | 0 | 0 |
11.
|
statistics
| 0.000014 | 0.000012 | 0.000001 | 0 | 0 |
12.
| preparing | 0.000013 | 0.000012 | 0.000002 | 0 | 0 |
13.
| executing | 0.000005 | 0.000005 | 0.000016 | 0 | 0 |
14.
| Sending data | 6.440260 | 7.818553 | 0.178155 | 0 | 0 |
15.
|
end
| 0.000008 | 0.000006 | 0.000011 | 0 | 0 |
16.
| query
end
| 0.000002 | 0.000002 | 0.000003 | 0 | 0 |
17.
| freeing items | 0.000030 | 0.000013 | 0.000017 | 0 | 0 |
18.
| logging slow query | 0.000001 | 0.000000 | 0.000001 | 0 | 0 |
19.
| logging slow query | 0.000035 | 0.000020 | 0.000015 | 0 | 0 |
20.
| cleaning up | 0.000003 | 0.000003 | 0.000000 | 0 | 0 |
21.
+
--------------------+----------+----------+------------+--------------+---------------+
22.
16
rows
in
set
(0.00 sec)
该profile显示了每一步操作的耗时以及cpu和Block IO的消耗,这样我们就可以更有针对性的优化查询语句了。可以看到,由于这是一次全表扫描,这里耗时最大是在sending data上。除了这种情况,以下几种情况也可能耗费大量时间:converting HEAP to MyISAM(查询结果太大时,把结果放在磁盘)、create tmp table(创建临时表,如group时储存中间结果)、Copying to tmp table on disk(把内存临时表复制到磁盘)、locked(被其他查询锁住) 、logging slow query(记录慢查询)。
s