思路:分析慢查询日志-查看表结构、表状态-查看表索引-分析sql语句-explain-修改sql语句-验证修改结果
在my.cnf置文件中修改
打开慢查询日志
long_query_time
设一个阀值,要大于这个值才会记录,等于该值时不记录。
log_queries_not_using_indexes
如果运行的SQL语句没有使用索引,则MySQl数据库同样会将这条SQL语句记录到慢查询日志文件
也可以在MySQL中直接设置long_query_time的值
Query OK, 0 rows affected (0.02 sec)
mysql> show variables like 'long%';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| long_query_time | 2 |
+-----------------+-------+
1 row in set (0.00 sec)
查看慢查询日志
tail -f slowquery.log
……
# Time: 110523 9:58:35 时间
# User@Host: grid[grid] @ [203.100.192.66] 连接信息
# Query_time: 4 Lock_time: 0 Rows_sent: 1 Rows_examined: 4815
查询时间 锁时间 返回行数 总共查询行数
select count(*) from table_name where ……
利用mysqldumpslow分析慢查询日志
mysqldumpslow -s r -t 10 返回记录集最多的10个查询
mysqldumpslow -s t -t 10 -g 'left join' 按照时间排序的前10条里面含有左连接的查询语句
-s, 是表示按照何种方式排序
c 记录次数、t 时间、l 查询时间、r 返回的记录数,ac、at、al、ar,表示相应的倒叙;
-t, 是top n的意思,即为返回前面多少条的数据;
-g, 后边可以写一个正则匹配模式,大小写不敏感的;
-s t | 按总query time排序 | -s at | 按平均query time排序 |
-s l | 按总locktime排序 | -s al | 按平均lock time排序 |
-s s | 按总row send排序 | -s as | 按平均row send排序 |
-s c | 按count排序 |
|
|
mysqlslowdump的输出结果会使用N和S代替SQL中出现的数字和字符串
mysqlslowdump输出结果是按照count(SQL出现的次数)排序的
mysqldumpslow结果分析
Reading mysql slow query log from slowquery.log
Count: 147973 Time=4.64s (686449s) Lock=0.34s (51032s) Rows=1.0 (147687), grid[grid]@[203.100.192.66]
select count(*) from table_name where ((newsT = 'S' and …………用S代表字符串
平均执行147973次,每次耗时4.64秒
分析问题
分析问题 查看当期表都有哪些索引
*************************** 1. row ***************************
Table: t 索引所在的表名
Non_unique: 0 非唯一索引,0代表唯一,可以看到主键名字是PRIMARY,因此必须唯一。
Key_name: PRIMARY 索引的名称,可以通过这个名称来DROP INDEX
Seq_in_index: 1 索引中该列的位置(注意理解是“索引中”),参考联合索引就容易理解了。
Column_name: a 索引的列
Collation: A 列以什么方式存储在索引中,可以是A或者NULL。B+树索引总是A,即排序的。如果使用了heap存储引擎,并建立了hash索引,这里就会显示NULL。因为hash根据hash桶来存放数据,而不是对数据进行排序。
Cardinality: 5 非常关键的值!!!表示索引中唯一值的数据的估计值。Cardinality值/表的行数,应尽可能接近1,如果非常小,那么考虑是否还需要这个索引???
Sub_part: NULL 是否是列的部分被索引,如果是整个列,则该字段为NULL
Packed: NULL 关键字如何被压缩,如果没有被压缩,则为NULL
Null: 是否索引的列含有NULL值。
Index_type: BTREE 索引的类型。
Comment: 注释
Index_comment:
Cardinality值(大概的值)非常关键,优化器会根据这个值来判断是否使用这个索引。但是这个值并不是实时更新的,并非每次索引的更新都会更新该值,因为代价太大。
更新索引的Cardinality信息
mysql> analyze table t \G
*************************** 1. row ***************************
Table: test.t
Op: analyze
Msg_type: status
Msg_text: OK
1 row in set (0.04 sec)
注意:不是每个系统上都得到同样的结果,目前(MySQL5.1),analyze table还存在一些问题。
建议:在非高峰时间,对应用程序下的几张核心表做analyze table操作,这能使优化器和索引更好的工作。
分析问题 explain
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
type: const
possible_keys: PRIMARY,idx_a_b
key: PRIMARY 优化器实际使用的索引
key_len: 4
ref: const
rows: 1
Extra:
1 row in set (0.00 sec)
select_type:表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(子查询中的第一个SELECT)等。
table:输出结果集的表。
type:表示表的连接类型,性能由好到差的连接类型为
system(表中仅有一行,即常量表)、
const(单表中最多有一个匹配行,例如primary key或者unique index)、
eq_ref(对于前面的每一行,在此表中只查询一条记录,简单来说,就是多表连接中使用primary key或者unique index)、
ref(与eq_ref类似,区别在于不是使用primary key或者unique index,而是使用普通的索引)、
ref_or_null(与ref类似,区别在于条件中包含对NULL的查询)、
index_merge(索引合并优化)、
unique_subquery(in的后面是一个查询主键字段的子查询)、
index_subquery(与unique_subquery类似,区别在于in的后面是查询非唯一索引字段的子查询)、
range(单表中的范围查询)、
index(对于前面的每一行,都通过查询索引来得到数据)、
all(对于前面的每一行,都通过全表扫描来得到数据)。
possible_keys:表示查询时,可能使用的索引。
key:表示实际使用的索引。
key_len:索引字段的长度。
rows:扫描行的数量。
Extra:执行情况的说明和描述。
Distinct
Not exists
Range checked for each
没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
Using filesort
Using index
Using temporary
Using where
分析问题 查看表状态
解决问题
参考:
源文档 <>
源文档 <>
源文档 <http://www.cnitblog.com/aliyiyi08/archive/2011/05/01/48878.html>